-------------------------------------------------------------------------- resource server profiles: stub,roles,audience -------------------------------------------------------------------------- Issuer state at the start: { "message": "ok", "activeKid": "stub-key-1", "publishedKids": [ "stub-key-1" ], "jwksFetches": 0 } -------------------------------------------------------------------------- 0. Warm the cache -------------------------------------------------------------------------- token signed with stub-key-1 GET /api/me -> 200 jwks fetches so far: 1 -------------------------------------------------------------------------- 1. PUBLISH a second key. Nothing signs with it yet. -------------------------------------------------------------------------- published: stub-key-2 { "message": "ok", "activeKid": "stub-key-1", "publishedKids": [ "stub-key-1", "stub-key-2" ], "jwksFetches": 1 } The resource server has not been told. Its cached JWK Set still holds one key. Old token still works: 200 jwks fetches so far: 1 <- unchanged: nothing forced a refresh -------------------------------------------------------------------------- 2. ACTIVATE the new key. The issuer starts signing with it. -------------------------------------------------------------------------- A token arrives whose kid is not in the cached JWK Set. New token: 200 jwks fetches so far: 2 <- the unknown kid forced one This is the recovery path, and it works. It is also the only thing in the default configuration that notices a rotation, because refresh-ahead is switched off. -------------------------------------------------------------------------- 3. Tokens signed with the old key are still in flight -------------------------------------------------------------------------- They were minted before the switch and have not expired yet. Old token: 200 <- still accepted, because the old key is still published -------------------------------------------------------------------------- 4. RETIRE the old key from the JWK Set -------------------------------------------------------------------------- retired: stub-key-1 { "message": "ok", "activeKid": "stub-key-2", "publishedKids": [ "stub-key-2" ], "jwksFetches": 2 } The resource server's cache still contains it, so nothing changes yet. Old token: 200 New token: 200 jwks fetches so far: 2 How long the old key keeps working from here is decided entirely by the cache. See retired-key-demo.sh, which runs this same step under two cache configurations.