next-auth JWT session decryption failed after secret rotation
Fixes next-auth JWT decryption failures after secret rotation with overlap handling. Use when sessions die on secret rotation. Key trigger: decryption failures right after rotation.
next-auth JWT session decryption failed after secret rotation
TL;DR
The NEXTAUTH_SECRET rotated and existing JWTs were encrypted with the old one, so every session fails decryption. Support both secrets during rotation (decrypt with old, encrypt with new), then retire the old. Rotating a session secret without overlap logs everyone out.
next-auth: JWT session decryption failed (after secret rotation)Steps
Confirm the timing: decryption failures start at the rotation. Expected: The cause is the new secret.
Add the old secret as a decryption fallback while issuing new tokens with the new secret. Expected: Old sessions decrypt again.
Let sessions naturally roll over to the new secret as they refresh. Expected: The old-secret population drains.
Remove the fallback after the max session lifetime passes. Expected: Only the new secret remains.
Document the overlap procedure for the next rotation. Expected: Rotations stop logging everyone out.
When to use
- next-auth sessions die after a secret rotation
- JWT decryption errors appear
- the secret recently changed
When not to use
- the secret did not change (check for corruption instead)
- using database sessions (different storage, different failure)
- the error is on token creation, not decryption (check the new secret's validity)
Tool compatibility
- next-auth / Auth.js
- JWT sessions
Variant phrasings
- "next-auth JWT decryption failed"
- "nextauth secret rotation sessions"
- "JWT session decryption failed secret"
Why it happens
JWT sessions are encrypted with the secret; rotation invalidates every outstanding token instantly. Without an overlap window, the rotation is a mass logout. The decrypt-with-old/encrypt-with-new pattern is the standard fix, and it needs to be planned before the rotation, not after.
Edge cases
- the overlap window must cover the max session lifetime, or long sessions still die
- the old secret must be retired, not kept forever; schedule its removal
- this applies to any JWT session secret, not just next-auth
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_BlCiVGvtUC5XrcWEsH5z3g