Our previous JWT issuer signed with a single key and didn't write a `kid` header. That works until the day you rotate.
The trap
You rotate the key. The new signer is happy. Tokens in flight signed by the previous key still need to verify — but verifiers don't know which key signed them, because the header is missing. So you either accept any key (defeats the point of rotation) or you reject everything signed before the rotation moment (mass session-invalidation event).
What we ship now
- Every `Sign` call writes a kid header sourced from the issuer's primary key id. - Verifiers reject tokens with missing or unknown kid — `invalid_token`. - Issuers carry a list of retired-but-still-trusted keys with a configurable grace window (default 24h).
The retired-key window is the trick: a token signed at T-1h with the old key still verifies at T+1h, so rotation is transparent to anyone currently signed in. After 24h the old key is purged.