Overview
Problem statement
After successful credential authentication the app did not redirect the user back to the original page. The sign-in
flow produced a session cookie (Auth.js / NextAuth), JWT callback logged, but the session callback did not run and middleware
outputs were absent. Pages that should be protected were accessible without authentication.
Short diagnosis:
Middleware was not executing because Next.js did not load the middleware module from the expected location / or the middleware imported node-only server modules causing it to be ignored by the edge bundler. Moving middleware to the expected path and making it edge-safe resolved the issue.
Solution
Fixes applied
- Move middleware to the correct location (
src/middleware.ts) to satisfy Next's discovery when the app uses src/.
- Make middleware edge-safe: avoid importing server-only modules (Prisma), and use
getToken from next-auth/jwt or withAuth from next-auth/middleware. This prevents Node-only code entering the edge bundle.
- Keep server-side auth separate: keep
auth.ts (NextAuth & PrismaAdapter) as a server-only module used by the API route /api/auth/[...nextauth].
- Ensure callback behavior: implement a
redirect callback in NextAuth to return the homepage when callbackUrl is missing (fallback to baseUrl).
Edge-safe middleware (recommended)
// src/middleware.ts (edge-safe)
import { NextResponse } from "next/server";
import { getToken } from "next-auth/jwt";
export async function middleware(req) {
const pathname = req.nextUrl.pathname;
if (pathname.startsWith('/api/auth') || pathname.startsWith('/_next') || pathname.startsWith('/favicon.ico')) return NextResponse.next();
const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET });
if (!token) {
const signInUrl = new URL('/api/auth/signin', req.url);
signInUrl.searchParams.set('callbackUrl', req.url);
return NextResponse.redirect(signInUrl);
}
return NextResponse.next();
}
export const config = { matcher: ["/((?!api/auth|_next|public|favicon.ico|.*\\.(?:png|jpg|jpeg|svg|gif|ico|css|js|map)).*)"] };
Redirect fallback in NextAuth
// inside auth.ts NextAuth options
callbacks: {
async redirect({ url, baseUrl }) {
if (!url) return baseUrl;
if (url.startsWith('/')) return baseUrl + url;
try {
const u = new URL(url);
if (u.origin === baseUrl) return url;
} catch(e) {}
return baseUrl;
}
}