Articles
JWT Key Rotation Interview Questions: JWKS Caches, kid, and Revocation
Practice JWT key rotation interview questions with a JWKS cache timeline, safe kid lookup, stale-key failures, and planned versus emergency revocation.
A JWT with a valid signature fails on one API replica but succeeds on another immediately after a signing-key rotation. The tempting answer is “increase the JWKS cache TTL” or “disable signature verification until the cache catches up.” Both miss the real interview problem: an issuer changes signing keys, verifiers hold different snapshots, and a token's untrusted header merely suggests which trusted key to try. A strong answer draws the timeline, identifies the authority for keys, and explains the failure policy.
This article focuses on asymmetric signed JWTs verified through an issuer-controlled JSON Web Key Set (JWKS). It is not a replacement for a broader authentication and authorization interview guide. The JWK specification defines the key-set format and kid; the JWT Best Current Practices supplies the security checks around key and algorithm selection.
Interview prompt: the same token, two results
Assume an issuer publishes public key K1 and signs access tokens with its private counterpart. Each token header says kid=K1. Two API replicas cache the issuer's JWKS. The issuer wants to switch to K2 without forcing all users to sign in again. Replica A refreshes its JWKS at 09:55; replica B will not perform its scheduled refresh until 10:10. At 10:00 the issuer begins signing new tokens with K2. At 10:01 a client sends the same new token to both replicas.
What happens, what should have happened before 10:00, and what should each replica do if it sees an unknown kid? Assume an illustrative five-minute token lifetime and a ten-minute maximum JWKS freshness window. These times are exercise inputs, not a standard or vendor guarantee.
The central invariant is that a verifier accepts a signature only under a public key obtained from the configured, trusted issuer; it then checks the token's expected algorithm, issuer, audience, validity interval, and application policy. kid is a lookup hint inside the untrusted token header. It does not grant permission to fetch a key from an arbitrary URL or to skip any claim check.
Draw the planned rotation timeline
At 09:50, the issuer can publish K2's public key in its trusted JWKS while continuing to sign with K1. A verifier that refreshes between 09:50 and 10:00 now knows both keys. At 10:00 the issuer switches only new signatures to K2. A K1 token issued at 09:59 may remain valid until its own expiry; removing K1 at 10:00 would break it. Only after the last intended K1 token has expired, with clock-skew and rollout margins defined by policy, can K1 normally leave the active verification set. Some providers have additional key states or revocation controls; the issuer's actual contract matters.
| Time in exercise | Issuer signs new tokens with | Trusted JWKS contains | What a correct verifier can accept |
|---|---|---|---|
| 09:45 | K1 | K1 | Valid K1 tokens only |
| 09:50 prepublish | K1 | K1, K2 | Valid K1 tokens; K2 ready for future use |
| 10:00 switch | K2 | K1, K2 | Valid unexpired K1 and valid K2 tokens |
| After K1 horizon | K2 | K2 after coordinated retirement | Valid K2 tokens; reject K1 |
Publishing before switching gives caches an overlap window. It does not prove every verifier has refreshed: a paused replica, proxy, SDK, CDN, or pinned certificate consumer may still be stale. Inventory all verifier classes and observe their cache age and key IDs before declaring the rollout complete. Auth0's signing-key rotation documentation illustrates a provider that exposes current, next, and sometimes previous keys. That is a useful concrete example, not a guarantee that every OIDC or custom issuer follows the same schedule.
The K1 retirement horizon depends on the last token signed with K1, not the first K2 token. Include maximum access-token lifetime, allowed clock skew, delayed delivery, and any documented offline verifier behavior. If the issuer cannot bound token lifetime or some verifiers pin a static certificate, a “seamless” rotation claim is not justified. State the expected availability impact and migration plan instead of pretending the cache will fix it.
What does kid actually select?
A signed JWT's protected header may contain alg and kid. The verifier can parse that header to choose a candidate key, but parsing is not trust. In RFC 7517, kid is a case-sensitive matching value; different keys in one JWK Set should use distinct values. A good implementation rejects ambiguous duplicate IDs under its issuer/key-type/algorithm policy and does not treat kid as a file path, SQL fragment, or remote endpoint.
Bind the accepted issuer to a configured JWKS location. Allow only expected signing algorithms and require the key type and algorithm to match. Do not use a token-provided jku or x5u as a new trust root: RFC 8725 warns that blindly following those header URLs can create server-side request forgery. Do not silently switch from an asymmetric algorithm to a symmetric one because a header said so. Reject alg=none unless the application deliberately uses the separate unsecured-JWT profile, which an authenticated API should not accidentally do.
Once the signature verifies, continue validating iss, aud, exp, and relevant nbf/token-type constraints. A K2 signature from a trusted issuer for another API is still not your authorization. The JWT registered-claims specification defines these claims; the application's validation policy supplies the expected values and tolerance. Finally evaluate scopes, roles, tenant, and object-level access at the requested operation, rather than declaring the token sufficient for every resource.
Debug the stale-cache failure without a refresh storm
In the prompt, A might have refreshed after K2 was published, while B still holds K1 alone. B's first K2 token should not be accepted merely because K2 appears in the header. A bounded on-demand refresh from the already configured issuer JWKS can repair this legitimate cache miss, followed by the normal signature and claim checks. If the refreshed, trusted set still lacks K2, reject the token and record a diagnostic that does not expose the token or key material. Whether a verifier does on-demand refresh at all is a product decision; the safety property is bounded trusted lookup and fail-closed validation.
An attacker can send thousands of random kid values. “Fetch JWKS on every miss” turns a cheap request into repeated network work and may overload the issuer. Coalesce concurrent refreshes, enforce a minimum refresh interval and timeout, bound response size and key count, cache negative misses briefly, and count unknown-ID rates. Preserve a known-good cache for keys that remain valid under policy during a transient fetch failure; do not trust an unknown key simply to preserve availability. Rate-limit abusive callers separately from legitimate rotation events.
Ask what the logs show: token kid, configured issuer identifier, cache generation and age, refresh outcome, validation-failure category, and verifier instance. Never log the raw bearer token. Compare A and B on the same token ID or safe fingerprint and same wall-clock interval. If both have K2 yet only B fails, the next suspects are algorithm allowlist, key parsing, clock drift, issuer/audience configuration, or claim policy, not cache freshness.
An interview-grade test matrix exercises four paths: K1 token during overlap; K2 token on a warm cache; K2 token on a stale cache with a successful bounded refresh; and unknown K9 after one allowed refresh. Add a JWKS timeout and a burst of random IDs. Expect no token to bypass signature or claim validation and no unbounded issuer calls. Test the old-key retirement boundary separately, including a token just before expiry and one just after.
Planned retirement versus compromised-key revocation
The normal timeline intentionally keeps K1 verification available for outstanding tokens. That is unacceptable if K1's private key is suspected stolen. An emergency response may stop new K1 signing, remove or revoke K1 from the issuer's trusted set, push cache invalidation or configuration updates to verifiers, and force affected sessions to reauthenticate. There can be an availability cost: legitimate K1 tokens may stop working before exp. Auth0's revocation documentation makes this provider-specific distinction explicit and warns to have the new key ready before revoking a previous one.
| Decision | Planned K1 retirement | Suspected private-key compromise |
|---|---|---|
| Main objective | Avoid rejecting still-valid K1 tokens | Stop accepting forged K1 signatures quickly |
| Key overlap | Keep K1 verification through bounded token horizon | Shorten or end K1 acceptance despite user impact |
| Cache behavior | Refresh by policy, monitor lag | Trigger trusted cache invalidation, observe convergence |
| User effect | Ideally transparent | Some sessions may require sign-in again |
| Proof of completion | No K1 issuance and no valid K1 tokens remain | All verifiers reject K1; investigate exposure and replay |
Even emergency JWKS removal is not instant across every cache unless the system has a measured invalidation path and fail policy. A verifier with stale K1 could still accept a forged token until its cache changes or its local deny policy activates. State a target convergence time, test it in drills, and know which gateways or offline services cannot meet it. If the same key signed multiple token kinds, enumerate all affected audiences and clients before declaring the incident contained.
Key revocation is also different from revoking one user's token. Removing K1 invalidates every token signed with K1, not just the stolen token. For selective immediate revocation, use a checked server-side session state, token identifier denylist, introspection, or another explicit freshness mechanism appropriate to the risk. Short access-token lifetime reduces the maximum natural exposure but is not zero-time revocation; refresh-token rotation controls later issuance but does not retroactively erase an already accepted access token. An interviewer will reward naming these separate levers.
A concise answer to give aloud
“I would prepublish K2 in the issuer's trusted JWKS, wait long enough for the defined verifier-cache policy, then sign new tokens with K2 while retaining K1 verification until the last legitimate K1 token expires. kid selects a candidate key only within the configured issuer set; it is not authority. On an unknown ID, I would allow at most a bounded, coalesced refresh from the configured JWKS and reject if no matching trusted key appears. Every accepted token still needs signature, algorithm, issuer, audience, time, and authorization checks. For a compromised key I would accept some session disruption, revoke K1, invalidate caches, and measure when every verifier actually rejects it. For a single stolen token I need session or token-specific revocation, not global key rotation.”
That answer is stronger than reciting a library method because it exposes the availability/security trade-off and names the observation that would prove the rotation worked. It also respects the boundary between cryptographic validation and business authorization. The suggested policy is editorial design reasoning; the exact issuer, SDK, cache headers, token lifetime, and emergency control plane must be discovered in the system at hand.
Sources and Further Reading
- RFC 7517: JSON Web Key (JWK) — JWKS and
kidsemantics. - RFC 7519: JSON Web Token (JWT) — registered claims and validation context.
- RFC 8725: JWT Best Current Practices — algorithm, key, and header safety.
- Auth0: Rotate Signing Keys — a documented provider rotation lifecycle.
- Auth0: Revoke Signing Keys — provider-specific emergency controls.