Rotating a signing key is not hard. What makes it go wrong is that the hard part is invisible: you must wait for other people’s caches.
The four steps
- Publish the new public key in your key set. Keep signing with the old one.
- Wait for consumers to refresh. Their cache lifetime sets this delay.
- Switch to signing with the new key. Leave the old public key published.
- Remove the old key once every token it signed has expired.
Steps 2 and 4 are waiting periods, and both are routinely skipped because nothing appears to break in a test environment where a single consumer refetches on every call.
Name your keys
Put a kid in every key and in every token header. Without it a verifier must try each key in turn, which works until two keys use the same algorithm and it starts guessing.
Use a name that says something: signing-2026-07 beats a random string when you are reading a log at two in the morning.
Set a sane cache lifetime
Serve your key set with an explicit Cache-Control. Too short and you take needless traffic. Too long and step 2 becomes a day. An hour is a reasonable starting point, and it makes the waiting period predictable, which is the whole point.
Rotate before you have to
A rotation you have practised on a Tuesday afternoon is a routine. The same operation, performed for the first time during a suspected compromise, is not.