Skip to content
All articles
Security18 May 2026·7 min read

Rotating a signing key when somebody else does the verifying

Encryption keys are rotated inside your own system. A signing key is verified on machines you do not control, which changes every step of the procedure.

Paycux security engineering

Rotating a key that encrypts data at rest is an internal exercise. You control every reader, you can version the ciphertext, and you can take as long as you like to re-encrypt in the background. Nobody outside your system has to know it happened.

A signing key is the opposite. The verifiers are other people's services, holding cached copies of your public key on a schedule you do not set, some of them running code that was deployed before you had the idea. Rotation becomes a coordination problem with parties who cannot be contacted, and the procedure has to work without their cooperation.

Publish, then sign, then retire

The safe sequence is fixed. Add the new key to the published key set while continuing to sign with the old one. Wait longer than the longest cache lifetime any reasonable verifier would use. Switch to signing with the new key while the old one remains published. Wait again, this time longer than the longest lifetime of any token already signed with the old key. Only then remove it.

The two waits are for different reasons and both are load-bearing. The first ensures no verifier meets a signature from a key it has never seen. The second ensures no token outlives its verifiable key. Compressing either produces failures at the far end that you will not see in your own metrics, because the errors happen in somebody else's process.

Both waiting periods look like doing nothing. They are the only two steps that prevent an error you will never see in your own logs.

The key identifier is the whole mechanism

None of this works without a key identifier in the token header. It tells the verifier which key to select from your published set, and it means holding several keys at once costs nothing. Without it, a verifier has to try each key in turn — workable but ambiguous — or it caches exactly one and breaks the moment you change it.

Publish the set at a stable, cacheable URL and set an honest cache header on it, because that number is the contract governing the first waiting period. Then handle the unknown identifier case deliberately on the verifying side: refetch once, with a rate limit, rather than either failing immediately or refetching on every miss. Failing immediately turns a rotation into an outage; refetching without a limit turns a malformed token into a way to make somebody hammer your endpoint.

  • Include a key identifier in the header from the first version, before you ever need one
  • Publish the key set at a stable URL with a cache lifetime you are prepared to honour
  • On an unknown identifier, refetch once under a rate limit rather than failing outright
  • Never accept a token that specifies its own verification key material

Compromise is not a slow rotation

Everything above optimises for nobody noticing. A suspected key compromise inverts the goal: the old key must stop being trusted now, and every token signed with it must stop working, including tokens held by legitimate users in the middle of their work.

That is a deliberately disruptive operation and it needs its own runbook and its own button. Remove the key from the published set, invalidate the sessions that depend on it, and accept that everybody signs in again. If your only implemented path is the graceful one, you will find yourself running a careful overlap while an attacker holds a valid signing key, which is the worst possible use of the procedure.

The verifiers you cannot see

Some verification happens where you have no visibility at all: a customer's gateway checking a token before it reaches their own service, a partner integration written two years ago, a script on somebody's machine. Those are the consumers who break, and the first you hear of it is a support message describing a failure in a system you have never seen.

Two things help. Make the key set endpoint boring and permanently stable — no authentication, no unusual headers, no redirects that break simple clients — because it is depended on by code you cannot inspect. And announce planned rotations, with dates, in the same place you publish other operational changes. Most integrators will do nothing with that notice, but the one who runs an offline verifier with a pinned key will act on it, and that is the one who would otherwise have filed the incident.

  • Keep the key set endpoint simple enough for the least sophisticated client you can imagine
  • Overlap for longer than the longest-lived token, not longer than the average one
  • Publish rotation dates in advance for the integrators who pin keys
  • Rehearse the emergency path, because its first run should not be during an incident

Everything here, already built

Sign-in, enterprise SSO, directory provisioning, roles and an audit trail behind one API. Start with the quickstart and have a working sign-in this afternoon.

Start selling to enterprise customers

Create an account, point sign-in at Paycux, and get back to the part of the product that is actually yours.