-------------------------------------------------------------------------- resource server profiles: stub,roles,nottlcache -------------------------------------------------------------------------- Scenario: a signing key is compromised. The issuer publishes a replacement and removes the compromised key from the JWK Set immediately. Tokens it signed are already out there with an hour left to run. 1. A token signed with stub-key-1, one hour to live: GET /api/me -> 200 jwks fetches: 0 2. Issuer rotates to stub-key-2 and retires stub-key-1. { "message": "ok", "activeKid": "stub-key-2", "publishedKids": [ "stub-key-2" ], "jwksFetches": 0 } Anyone fetching /jwks.json from this moment sees only stub-key-2. 3. From here the ONLY traffic is the leaked token. Nothing carries an unknown kid, so nothing forces a refresh. Whether the token keeps working is decided purely by whether the cached JWK Set expires. elapsed leaked jwksFetches t+0s 200 0 t+30s 200 0 t+60s 200 0 t+90s 200 0 t+120s 200 0 t+150s 200 0 t+180s 200 0 t+210s 200 0 t+240s 200 0 t+270s 200 0 t+300s 200 0 t+330s 200 0 t+360s 200 0 t+390s 200 0 t+420s 200 0 t+450s 200 0 A row that flips to 401 is the cache expiring and the retired key going away. A column of 200s is a resource server that has not noticed, and will not, until something happens to bring it a token it cannot verify.