Rotating signing keys without breaking active sessions requires the kid header and a JWKS endpoint. Here's how the mechanism works end to end.
Why you need to rotate at all
Signing keys shouldn't live forever — the longer a key is in use, the larger the blast radius if it's ever compromised, and the harder it becomes to prove it wasn't. Regular rotation is a baseline security hygiene practice, similar to rotating database credentials or TLS certificates.
The naive approach breaks active sessions
If you simply swap your signing key at a fixed instant, every token signed with the old key immediately fails verification, forcing every logged-in user to re-authenticate at once. For an access token with a 10-minute lifetime this is barely noticeable; for anything longer-lived, it's a real disruption. The fix is to support **multiple valid keys simultaneously** during a rollover window.
`kid`: the key identifier
The `kid` header field lets a token declare which key it was signed with, by ID, not by value. When your verifier receives a token, it reads `kid`, looks up the corresponding public key (for RS256/ES256) or secret (for HS256) in your key store, and verifies against that specific key — never the token's claimed algorithm, only which pre-registered key to use.
JWKS: publishing public keys
For asymmetric algorithms, a **JSON Web Key Set (JWKS)** is a standard JSON document, typically served at `/.well-known/jwks.json`, listing your current public keys, each tagged with its own `kid`. Any resource server can fetch this document, cache it, and use it to verify tokens without ever having direct access to your private signing key. This is exactly how most OIDC providers (Auth0, Okta, Google) let arbitrary third parties verify their tokens.
A practical rotation procedure
1. Generate a new key pair (or new HMAC secret) and assign it a new `kid`.
2. Add the new key to your JWKS document (or key store) **alongside** the old one — don't remove the old key yet.
3. Start signing new tokens with the new key and its `kid`.
4. Keep the old key available for verification only, for at least as long as your longest-lived outstanding token (e.g., your refresh token lifetime).
5. Once you're confident no valid token still references the old `kid`, remove it from the JWKS document and key store.
HMAC key rotation is a little different
Since HS256 has no public component to publish, rotation means maintaining a small internal map of `kid → secret` and doing the same overlap-then-retire process, just without a public JWKS endpoint. The mechanics are otherwise identical.
Caching considerations for JWKS consumers
Verifying servers should cache the fetched JWKS document rather than fetching it on every request, but the cache needs a sensible TTL (minutes, not days) so a genuinely rotated key is picked up promptly. Most JWKS client libraries also support handling an unknown `kid` by forcing a cache refresh once, in case rotation happened since the last fetch.
Common mistakes
- Rotating without an overlap window, breaking every active session at the rotation instant.
- Forgetting to remove old keys eventually, letting a compromised key remain trusted indefinitely.
- Publishing a JWKS document without cache headers, causing unnecessary load, or with an overly long cache TTL, delaying rotation propagation.
- Using the same `kid` for two different keys during a botched rotation — always use a fresh, unique identifier.
Checklist
- Assign every signing key a unique `kid` from day one, even before your first rotation.
- Support multiple simultaneously valid keys during rollover.
- Retire old keys only after their maximum possible token lifetime has elapsed.
- Serve a properly cache-controlled JWKS document if you use asymmetric algorithms.
- Automate rotation on a schedule rather than waiting for an incident to force it.