Rotating signing keys without breaking anyone

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

  1. Publish the new public key in your key set. Keep signing with the old one.
  2. Wait for consumers to refresh. Their cache lifetime sets this delay.
  3. Switch to signing with the new key. Leave the old public key published.
  4. 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.