fix(auth/middleware): recognize chunked session cookies
NextAuth v5 chunks the session cookie when the JWT payload exceeds ~4KB (we hit this easily: keycloakId + tenantId + display names + roles + accessToken JWT + idToken). When chunked, the bare 'authjs.session-token' cookie is removed in favour of 'authjs.session-token.0', '.1', etc. Looking up only the bare name returned undefined and the middleware redirected freshly-logged-in users back to /api/auth/signin in a loop. Match presence-only on any cookie whose name starts with either canonical prefix. Server-side NextAuth still validates the token on every RSC render — this check only gates the redirect. Repro: gscCRM/v2.3.3 with the proxy fix in place. Keycloak auth completes, /api/auth/callback/keycloak 302s, but every subsequent request to / 307s straight back to signin because the middleware doesn't see the now-chunked cookie. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ interface NextRequestLike {
|
||||
nextUrl: URL;
|
||||
cookies: {
|
||||
get(name: string): { value: string } | undefined;
|
||||
getAll(): Array<{ name: string; value: string }>;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -62,10 +63,7 @@ export function createAuthMiddleware(opts: AuthMiddlewareOptions = {}) {
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
const sessionCookie =
|
||||
req.cookies.get("authjs.session-token") ??
|
||||
req.cookies.get("__Secure-authjs.session-token");
|
||||
if (sessionCookie) {
|
||||
if (hasSessionCookie(req)) {
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
@@ -75,6 +73,32 @@ export function createAuthMiddleware(opts: AuthMiddlewareOptions = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* NextAuth v5 chunks the session cookie when the JWT payload exceeds
|
||||
* ~4 KB (claims + accessToken + roles add up fast). When chunked, the
|
||||
* bare `authjs.session-token` cookie is *removed* in favour of
|
||||
* `authjs.session-token.0`, `.1`, etc. Looking up only the bare name
|
||||
* misses the chunked form and the middleware loops the user back to
|
||||
* signin even though they have a valid session.
|
||||
*
|
||||
* Match presence-only on any cookie whose name starts with either
|
||||
* canonical prefix. Token validity is still verified server-side by
|
||||
* NextAuth on every RSC render — this check only gates the redirect.
|
||||
*/
|
||||
function hasSessionCookie(req: NextRequestLike): boolean {
|
||||
for (const c of req.cookies.getAll()) {
|
||||
if (
|
||||
c.name === "authjs.session-token" ||
|
||||
c.name === "__Secure-authjs.session-token" ||
|
||||
c.name.startsWith("authjs.session-token.") ||
|
||||
c.name.startsWith("__Secure-authjs.session-token.")
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isAlwaysAllowed(pathname: string): boolean {
|
||||
return (
|
||||
pathname.startsWith("/api/auth/") ||
|
||||
|
||||
Reference in New Issue
Block a user