auth.isdocs
Features

Signing keys

Every issuer signs its ID tokens and per-resource JWT access tokens with its own RS256 key, and publishes the public half at its JWKS endpoint so relying parties can verify signatures. Keys rotate through three explicit states, so a rotation is zero-downtime: tokens signed before, during, and after stay verifiable throughout.

JWKS discovery

The issuer's discovery document advertises a jwks_uri:

https://{slug}.auth.is/oidc/jwks

Your OIDC library fetches and caches those public keys and picks the one matching a token's header kid to verify its signature. You never handle private key material — it is decrypted only inside the IDP at provider-build time, never logged, never returned by any API, never in a view. The management API's key views carry only the kid, status, and timestamps — never the public or private JWK. The jwks_uri is the one and only public-key surface.

The three-state lifecycle

StatusIn JWKS?Signs?Meaning
nextyesnoPublished ahead of promotion so RPs pre-cache it.
activeyesyesThe current signer — first in the JWKS array.
retiredyesnoKept published so already-issued tokens still verify.

The ordering is the mechanism. The IDP returns keys ordered active → next → retired, and oidc-provider signs with the first suitable key in the array — so whichever key is active, and only it, signs. next and retired are verify-only.

The rotation runbook

Rotate from the MCP with rotate_signing_keys, or from the CLI with keys:rotate — both drive the same three steps. Each transition bumps the issuer's configVersion transactionally and evicts the running provider, so every node serves the new JWKS without a restart (see Issuers on instant invalidation).

pnpm keys:rotate --issuer <slug> --step prepare
pnpm keys:rotate --issuer <slug> --step promote
pnpm keys:rotate --issuer <slug> --step retire [--older-than <days>] [--force]
  1. Prepare mints a fresh next key and publishes it — but nothing signs with it yet. This lets RPs fetch and cache the new key before it starts signing, so promotion never races a cold JWKS. Wait at least one JWKS cache lifetime (a few hours is ample) before promoting.
  2. Promote flips next → active (it signs now) and the old active → retired (still published). New tokens are signed by the new key; tokens minted before promotion still verify against the retired key.
  3. Retire drops retired keys older than the safety window (default 60 days) from the JWKS. Keys still inside the window are kept.

The tooling is idempotent-safe: re-running a step that does not apply (a second prepare, a promote with no next) exits without changing anything. It prints the before/after key states (kids + statuses only — never private material) and the new configVersion.

Compromise: roll forward now

There is no "un-promote". If a promoted key misbehaves, prepare + promote again to roll forward to a third key. If a private key is compromised, do not wait out the window — roll forward and force-drop the bad key immediately:

pnpm keys:rotate --issuer <slug> --step prepare
pnpm keys:rotate --issuer <slug> --step promote
pnpm keys:rotate --issuer <slug> --step retire --force

Next steps