JWT Signing-Key Rotation¶
Applies to: All subscriptions — today this applies to dev and QA only; production is not yet cut over to Key Vault, see Environment Variables
Purpose¶
Replace the secret that signs login sessions — on a schedule, or immediately after a suspected leak — without forcing every signed-in user to log in again.
Audience¶
The operator who runs a rotation, and the system administrator who confirms it.
Prerequisites¶
- Key Vault Secrets Officer access on the target environment's vault
KEY_VAULT_URLset on every node of that environment
Steps¶
1. Know the one fact that matters¶
A rotation does not force a re-login as long as it stays inside the 48-hour overlap window. Outside that window — or on production, which is not yet on this path — changing the signing key ends every session immediately.
| During the 48-hour window | After the window |
|---|---|
| New logins get the new key | Only the new key is accepted |
| A session from before the rotation still works | A session signed with the retired key is rejected; that user must log in again |
| Both keys are logged as in use (see step 3) | Only the new key should appear in the logs |
2. Rotate the key¶
- In the target vault (
complifly-kv-devorcomplifly-kv-qa), copy the current value ofjwt-signing-keyintojwt-signing-key-previous. - Generate a new value for
jwt-signing-key. Record a new key identifier for it (for example2026-10-b) — setJWT_KEY_IDto the new identifier andJWT_PREVIOUS_KEY_IDto the one just retired. - Set
JWT_PREVIOUS_VALID_UNTILto the current time plus 48 hours. - Restart the application on each node, one at a time, waiting for each to pass its health check before moving to the next.
3. Monitor the rotation¶
Every successful login check is counted and written to the audit trail as an aggregated event (not one row per request) — see Audit Log Review. Look for:
JWT_KEY_CURRENT_VERIFIED— logins succeeding on the new key.JWT_KEY_PREVIOUS_VERIFIED— sessions still on the old key. This should fall to zero across the 48-hour window as old sessions expire or users re-authenticate naturally.JWT_KEY_REJECTED— a token presented an unrecognised key identifier. A small, steady number is normal (stale browser tabs, old mobile sessions); a sudden spike after retiring the previous key means it was removed too early.
4. Retire the previous key¶
At or after JWT_PREVIOUS_VALID_UNTIL, confirm no sessions are still using the
previous key (JWT_KEY_PREVIOUS_VERIFIED has fallen to zero), then remove
jwt-signing-key-previous from the vault. It is not safe to remove it while that
event is still being logged.
5. Emergency rotation (suspected key leak)¶
Run steps 2–4, but skip the overlap: set JWT_PREVIOUS_VALID_UNTIL to the
current time (or leave jwt-signing-key-previous unset). Every session ends
immediately and users sign in again once. This is a deliberate trade — a possibly
compromised key staying valid for 48 more hours is the greater risk.
Validation¶
- New logins succeed immediately after each node restarts.
- Sessions that existed before the rotation keep working for the rest of the 48-hour window (confirm with one real account rather than assuming it).
- The audit trail shows
JWT_KEY_CURRENT_VERIFIEDgrowing andJWT_KEY_PREVIOUS_VERIFIEDfalling toward zero across the window. - After retiring the previous key, no new
JWT_KEY_PREVIOUS_VERIFIEDevents appear.
Troubleshooting¶
| Symptom | Cause | Action |
|---|---|---|
| Users signed out shortly after a routine rotation | JWT_PREVIOUS_VALID_UNTIL was set in the past, or omitted |
Confirm the value before restarting the next node |
JWT_KEY_REJECTED spikes right after retiring the previous key |
Some sessions had not yet re-authenticated | Expected for a small number; if it is large, the window was likely too short for this environment's traffic |
| Rotation on production forces every session out | Production is not yet on Key Vault for JWT_SECRET |
Expected today — see Environment Variables for current status |
Related Articles¶
- Environment Variables — the five rotation-related settings and their defaults
- Audit Log Review — where the rotation's audit events land
- Login and Access Failures