nextauthjs/next-auth · error
Invalid JWT
Error message
Invalid JWT
What it means
When the session strategy is 'jwt', Auth.js decodes the session token cookie using jose with the configured secret and cookie name as salt. If decoding returns no payload (malformed, tampered, or undecryptable token), it throws 'Invalid JWT', which aborts session retrieval.
Source
Thrown at packages/core/src/lib/actions/session.ts:47
...(!isUpdate && {
"Cache-Control": "private, no-cache, no-store",
Expires: "0",
Pragma: "no-cache",
}),
},
cookies,
}
const sessionToken = sessionStore.value
if (!sessionToken) return response
if (sessionStrategy === "jwt") {
try {
const salt = options.cookies.sessionToken.name
const payload = await jwt.decode({ ...jwt, token: sessionToken, salt })
if (!payload) throw new Error("Invalid JWT")
// @ts-expect-error
const token = await callbacks.jwt({
token: payload,
...(isUpdate && { trigger: "update" }),
session: newSession,
})
const newExpires = fromDate(sessionMaxAge)
if (token !== null) {
// By default, only exposes a limited subset of information to the client
// as needed for presentation purposes (e.g. "you are logged in as...").
const session = {
user: { name: token.name, email: token.email, image: token.picture },
expires: newExpires.toISOString(),
}
// @ts-expect-errorView on GitHub (pinned to a1a16a5a77)
Solutions
- Ensure AUTH_SECRET/NEXTAUTH_SECRET is set to the same stable value across all environments and instances sharing session cookies
- Log the user out (delete the session cookie) so a fresh token is issued on next sign-in — old invalid cookies cannot be recovered
- If migrating next-auth v4 to v5, expect old JWT cookies to be invalid and force re-authentication, or keep the legacy secret during a transition window
- Confirm you are not mixing 'database' and 'jwt' strategies with cookies written by the other mode
- Verify no middleware or proxy rewrites/truncates the session cookie (large cookies can be split or dropped)
Example fix
// before
// no secret pinned; each deploy generates a new one
// after
export const { handlers, auth, signIn, signOut } = NextAuth({
secret: process.env.AUTH_SECRET, // stable across deployments
session: { strategy: 'jwt' },
}); Defensive patterns
Strategy: try-catch
Validate before calling
function isSessionCookieShaped(v: string | undefined): boolean {
return !!v && v.split('.').length >= 2 && v.length > 20; // JWE/JWT-like shape
} Type guard
function hasPayload(p: unknown): p is Record<string, unknown> {
return typeof p === 'object' && p !== null && 'sub' in (p as object);
} Try / catch
try {
const session = await auth();
} catch (e) {
if (/Invalid JWT/.test(String(e))) {
// clear the stale session cookie and redirect to sign-in
await signOut({ redirect: false });
}
} Prevention
- Pin AUTH_SECRET/NEXTAUTH_SECRET in env, identical across all instances and deploys
- Force re-login after major version migrations (v4 to v5 changes token format)
- Do not mix 'database' and 'jwt' session strategies on the same cookies
- Monitor for cookie-stripping middleware/proxies truncating large session cookies
When it happens
Trigger: The sessionToken cookie exists but its payload cannot be decoded: cookie encrypted/signed with a different AUTH_SECRET, token from another deployment/environment, manually crafted cookie value, or a token corrupted by truncation.
Common situations: Changing or losing NEXTAUTH_SECRET/AUTH_SECRET between deploys while users hold old cookies; running multiple instances with different secrets; switching between next-auth v4 and Auth.js v5 (different token formats); copying session cookies between localhost and production.
Related errors
- no matching decryption secret
- Couldn't create session
- Dgraph client error: Please provide an API key
- Dgraph client error: Please provide a valid GraphQL endpoint
- Unsupported database type (${typeof db}) in Auth.js Drizzle
AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28).
Data as JSON: /api/errors/bba71756f18cf8bc.
Report an issue: GitHub.