Files
goodgo-platform/docs/security/secret-rotation.md
Ho Ngoc Hai 6afe4fd626 feat(auth): implement dual-key JWT verification for zero-downtime rotation
Add JWT_SECRET_NEXT env var support for seamless JWT secret rotation:

- JwtStrategy: use secretOrKeyProvider to try primary then fallback key
- TokenService.verifyAccessToken(): dual-key fallback for internal callers
- Redis metric jwt_verify_with_next_total for monitoring cut-over progress
- Session revocation marker support restored in JwtStrategy.validate()
- Unit tests for all three verification scenarios (primary, fallback, both-fail)
- docs/security/secret-rotation.md runbook with step-by-step rotation procedure

Closes GOO-203.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-24 12:08:34 +07:00

1.1 KiB

JWT Secret Rotation Runbook

Zero-downtime JWT secret rotation using dual-key verification.

Environment Variables

Variable Required Description
JWT_SECRET Yes Primary signing and verification key
JWT_SECRET_NEXT No Fallback verification-only key during rotation

How It Works

  • Signing: Always uses JWT_SECRET (primary). Tokens are never signed with _NEXT.
  • Verification: Tries JWT_SECRET first. On failure, falls back to JWT_SECRET_NEXT if set.
  • Metric: Each fallback verification increments metrics:jwt_verify_with_next_total in Redis.

Rotation Procedure

  1. Generate new secret: openssl rand -base64 48
  2. Deploy with JWT_SECRET=<old>, JWT_SECRET_NEXT=<new>
  3. Swap: JWT_SECRET=<new>, JWT_SECRET_NEXT=<old>
  4. Wait 15 minutes (access token TTL)
  5. Drop JWT_SECRET_NEXT
  6. Verify no 401 spikes

Rollback

Swap back: JWT_SECRET=<old>, JWT_SECRET_NEXT=<new>.

Emergency: Forced Re-login

Rotate to a new secret without setting _NEXT. All existing tokens become invalid.