v0.0.1 · system status
Open APIOpenAPI 3.1Zero token storage

Validate JWKS rotation

Classify the rotation state between two JWKS snapshots.

POST /v1/validate/jwks-rotation Classify the rotation state between two JWKS snapshots.

Compares a previous_jwks snapshot with a current_jwks snapshot, classifies the rotation, and optionally verifies sample tokens against each side. Designed to run as a periodic check (cron, scheduled CI job) so rotations are caught before in-flight tokens start failing.

Request

body — application/json
Field Type Required Description
previous_jwks JWKS yes Last-known JWKS document. Object with a keys array.
current_jwks JWKS yes Current JWKS document.
overlap_policy object no Operational thresholds. min_overlap_count: minimum number of shared kids required for safe_overlap. max_token_ttl_seconds: longest in-flight token lifetime; informs the recommended grace period.
sample_token string no A token whose signature should verify against current_jwks. Use to spot-check that the new key set produces the expected key for the kid on a fresh token.
sample_old_token string no A token issued under the previous key set. Should still verify under current_jwks during a safe overlap.
sample_new_token string no A token signed with a key only in current_jwks. Confirms the new key is in service.

Response — 200

body — application/json
Field Type Required Description
rotation_state "no_change" | "safe_overlap" | "overlap" | "disjoint" yes See Rotation states below.
findings Finding[] yes Operational concerns. Empty when state is no_change or safe_overlap within policy.
summary string yes One-sentence description.

Rotation states

StateMeaning
no_changeprevious_jwks == current_jwks. No rotation in progress.
safe_overlapAll previous keys still present in current_jwks, plus at least one new key. New tokens can be issued under the new key while old tokens continue to verify. The desired state during a rotation.
overlapSome, but not all, previous keys remain. Tokens issued under the dropped previous keys will fail verification. Only safe if you can guarantee no in-flight tokens reference the dropped keys (e.g. their kids have been retired for longer than max_token_ttl_seconds).
disjointNo keys in common. Every in-flight token issued under the previous set will fail. Roll back, or accept a verification outage during cutover.
200 rotation in progress with safe overlap — recommended state
{
  "rotation_state": "safe_overlap",
  "findings": [
    {
      "code": "ROTATION_IN_PROGRESS",
      "severity": "warning",
      "message": "Rotation in progress: 1 new key added, all previous keys retained.",
      "evidence": {
        "shared_kids": [
          "k1"
        ],
        "new_kids": [
          "k2"
        ],
        "dropped_kids": []
      }
    }
  ],
  "summary": "JWKS rotation state: safe overlap (in-progress rotation)."
}
Disjoint state is an outage

A disjoint result with no rollback path means in-flight tokens will fail signature verification immediately. Do not advance rotations into disjoint; require safe_overlap for at least max_token_ttl_seconds first.

Errors

ChannelCodeCause
200, in findingsNO_KEY_OVERLAPCurrent set shares zero keys with previous.
200, in findingsROTATION_IN_PROGRESSSafe overlap detected (informational).
200, in findingsROTATION_UNCLEARJWKS lacks the metadata (e.g. kid) needed to classify.
422Missing previous_jwks or current_jwks.

Example

curl -sSf -X POST "$JWTSHIELD_URL/v1/validate/jwks-rotation" \
  -H "Authorization: Bearer $JWTSHIELD_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "previous_jwks": { "keys": [{"kid":"k1","kty":"RSA","n":"...","e":"AQAB"}] },
    "current_jwks":  { "keys": [{"kid":"k1","kty":"RSA","n":"...","e":"AQAB"},
                                {"kid":"k2","kty":"RSA","n":"...","e":"AQAB"}] },
    "overlap_policy": { "min_overlap_count": 1, "max_token_ttl_seconds": 86400 }
  }'

See JWKS rotation guide for the operational pattern around this endpoint.