skip to content

In OpenID Federation 1.0, how can a Trust Chain signed under a since-retired federation key still be validated?

level: seniorimportance: nice to knowfreq 22%

answer

  1. your Superior attests your key
  2. old statements outlive the rotation
  3. withdrawn keys keep a timestamp and a reason
  4. superseded and compromised are opposites
  5. three values only, no others

basics

~20 s

Through the federation_historical_keys_endpoint, where an entity publishes the keys it has used, each retired one marked with revoked_at and a reason of unspecified, compromised or superseded. A verifier can then judge signatures made before the key was withdrawn.

solid answer

~40 s

A federation entity's keys are attested from above, so a rollover is never a purely local act: statements already issued under the old key stay in circulation until they expire. To make those judgeable, an entity may publish a `federation_historical_keys_endpoint` — a signed JWT whose `keys` member lists the keys it has used, with each retired key carrying `revoked_at` and a `reason` of `unspecified`, `compromised` or `superseded`. A verifier holding an old statement can check whether the signing key existed and was still in service at the statement's `iat`. The `reason` is what makes the judgement: `superseded` means an orderly rotation, so signatures made before `revoked_at` remain meaningful, while `compromised` means the key may have been in someone else's hands and its signatures cannot be assumed authentic.

code

json · 16 lines
json
{
  "iss": "https://intermediate.schools.example",
  "iat": 1758240000,
  "keys": [
    {
      "kty": "RSA", "use": "sig", "kid": "fed-2025a",
      "n": "pjdss8ZaDf…", "e": "AQAB",
      "revoked_at": 1756684800,
      "reason": "superseded"
    },
    {
      "kty": "RSA", "use": "sig", "kid": "fed-2026a",
      "n": "0vx7agoebG…", "e": "AQAB"
    }
  ]
}

go deeper

for a junior

Recall that a federation publishes a record of the signing keys it has used, not just the current ones, so that something signed last year can still be made sense of.

for a middle

Explain the lookup: find the key by kid in the historical set, compare the statement's iat with revoked_at, and read the reason before deciding.

for a senior

Show why the reason value changes the verdict, and why a rollover needs the Superior to reissue before old statements stop naming the retired key.

for a principal

Set the statement lifetimes that decide how long a rollover takes to propagate, and the disclosure practice that makes a compromised key legible to parties you cannot contact directly.

## Why a federation key rollover is not a private matter Within one issuer, rotating a signing key is a local operation: publish the new key, sign with it, retire the old one. In a multilateral federation, the key an entity signs with is **attested by its Superior**, inside the **Subordinate Statement** about it. Until that Superior issues a fresh statement, every **Trust Chain** anyone builds still names the old key — so the entity cannot complete a rollover by itself, and cannot control how long statements naming the old key remain in circulation. Their lifetime is the `exp` its Superior chose. This is the mechanism, and only the mechanism: how a federation decides to sequence an overlap, and what it does when a key has been held by someone else for a year, is an incident and negotiation question rather than a protocol one. ## The historical keys endpoint A federation entity may publish `federation_historical_keys_endpoint` in its `federation_entity` metadata. It returns a signed JWT whose `keys` member is a JWK Set covering the keys the entity has used — current ones and withdrawn ones together. A withdrawn key carries two extra members: - `revoked_at` — when it left service; - `reason` — one of `unspecified`, `compromised` or `superseded`. That turns "this `kid` is not in the current set" from a dead end into a decidable question. ## What a verifier does with it Given a statement signed by a `kid` that is no longer current: 1. Fetch the issuer's historical keys and find the key by `kid`. 2. Compare the statement's `iat` with the key's `revoked_at`. 3. Read `reason` and decide. The decision differs sharply by reason: | `reason` | What it says | Reasonable handling | |---|---|---| | `superseded` | Rotated out in the normal course | A signature made before `revoked_at` remains meaningful | | `compromised` | The private key may be in other hands | Signatures cannot be assumed authentic, including earlier ones | | `unspecified` | No reason given | Treat conservatively; you cannot distinguish the two cases above | The distinction matters because those two cases are opposites. `superseded` is housekeeping: nobody else ever held the key, so what it signed while in service is as good as it ever was. `compromised` means the binding between key and entity was broken at an unknown moment, and "it was signed before the revocation timestamp" stops being reassuring. ## Where this is actually used Three situations, none of them the live login path: - **Rollover overlap.** Parties that cached a chain or a statement before the rotation can still make sense of it instead of hard-failing while the federation catches up. - **Audit after the fact.** Someone asks, months later, whether a statement was legitimately issued. The key it names is long gone from the current set, and the historical set is what answers the question. - **Compromise triage.** Publishing `compromised` rather than quietly dropping a key tells every relying party which past material to stop believing. ## Neighbouring mechanisms it is not This is not certificate revocation: there is no X.509 certificate, no revocation list, and the `revoked_at` member is a timestamp inside a JWK Set, not a serial number in a directory. It is also not the rotation of the key an issuer signs its own login responses with, which is that issuer's internal operation and reaches relying parties through its own published key set. A federation entity may publish its federation keys inline as `jwks` or by reference as `signed_jwks_uri`; the historical endpoint is the third thing, the record of what has been used and what has been withdrawn.

  • Why can a federation entity not complete a key rollover on its own?
    Because the keys a verifier honours for that entity are the ones its Superior attested in the Subordinate Statement about it, not the ones the entity publishes about itself. Until the Superior issues a fresh statement, chains built by anyone still name the old key, and the old statements keep working until their own `exp`.
  • How should a verifier treat a key withdrawn with reason compromised differently from superseded?
    `superseded` is an orderly rotation, so signatures made while the key was in service stay meaningful and old statements can be read normally. `compromised` says the private key may have been held by someone else from an unknown moment, so `revoked_at` no longer divides good signatures from bad ones and the sensible response is to stop relying on what that key signed.
  • Is this the same as certificate revocation?
    No. There is no certificate and no revocation list: the record is a JWK Set inside a signed JWT, keyed by `kid`, where a withdrawn key carries `revoked_at` and `reason`. The X.509 world answers a yes-or-no question about a certificate; this answers "was this key in service when that statement was signed, and why did it leave?"

saying these in an interview costs you the question

  • Thinks retiring a key voids every statement it ever signed
  • Handles compromised and superseded identically
  • Believes an entity can rotate its federation key unilaterally
  • Expects a certificate revocation list to cover federation signing keys
  • Confuses this with rotating the key that signs login responses