Architecture Decision Record

0023. Key rotation, JWKS publication, and multi-key lifecycle

Context

ADR-0003 made signing-key custody a trait (KeyCustody) but deliberately left most of its surface to be filled in later. The operational lifecycle of those keys is that surface, and it is constitution-critical, because the public half of every signing key is what Vör reads to verify (ADR-0010). Two latencies are in tension: keys should rotate often (security), but the edge caches public material, so a token signed with a key the edge has not yet seen would fail verification. The JWKS is also the clearest case of a read that must be a cached projection, never a core read on the hot path (rule 1). This ADR fixes the rotation and publication model.

Decision

  1. Multiple concurrent keys, kid-addressed. At any time Vord holds a current signing key, a next key, and one or more retiring keys, each identified by its kid. Tokens carry their kid (ADR-0003); a verifier selects the matching public key from the JWKS. Per-tenant/realm key separation (ADR-0012) is the cryptographic isolation boundary.

  2. JWKS is a derived, edge-cached projection — never a hot-path core read. The published JWKS is a projection of the key set (ADR-0022), cached at the edge and refreshed on a short interval, exactly like the status list (ADR-0005). Vör reads the cache, not the core (ADR-0010, rule 1). Private keys are core/HSM-resident and never hot-path-read (rule 2); only public material is ever distributed.

  3. Rotation overlaps, then retires — no orphaned token. A new key is published to the JWKS before it is first used to sign (publish-before-sign), so the edge has learned the new kid before any token bearing it arrives. The retiring key stays published until every token it signed has expired (the overlap window ≥ the max token TTL), so no in-flight token is left unverifiable. Retirement removes the public key only after that window.

  4. Key-distribution latency is the named dual of revocation latency. Just as revocation has a propagation budget (ADR-0005), key introduction has one: the interval between publishing a new kid and signing with it must exceed the edge JWKS-cache staleness bound. It is a stated budget and a security/freshness-plane signal, not an afterthought.

Consequences

  • Aggressive rotation and edge caching coexist: publish-before-sign plus the overlap window mean rotation never produces a verification failure, so keys can rotate on a security-driven schedule without operational fear.
  • The JWKS, the status list (ADR-0005), and the future SAML signing certificate (ADR-0017) are sibling edge-cached projections of core-resident authoritative material — one pattern, three artifacts, all keeping the verification path core-independent.
  • KMS/HSM unavailability affects issuance only (new signatures), never verification (which reads cached public keys) — the constitution working as intended (ADR-0010 §3), and the failure-domain note ADR-0008 flags for KeyCustody.
  • Production keys are a milestone of the implementation arc (M1); M0 uses a single embedded-keystore key with rotation reserved, so the walking skeleton stays small while the seam and the kid discipline exist from the first token.