Skip to content
JWKS: Key Set + kid Lookup
step 1/5

Reading — step 1 of 5

Read

~1 min readSecurity & Operations

JWKS: JSON Web Key Set

Real-world auth providers (Auth0, Okta, Google, AWS Cognito, Microsoft Entra) expose /.well-known/jwks.json. The response is a JSON Web Key Set (RFC 7517 Section 5):

{
  "keys": [
    {"kty":"RSA","kid":"2024-01","alg":"RS256","n":"...","e":"AQAB","use":"sig"},
    {"kty":"RSA","kid":"2024-07","alg":"RS256","n":"...","e":"AQAB","use":"sig"}
  ]
}

Each key has a kid (key ID). When you receive a JWT, you:

  1. Read header.kid.
  2. Look it up in your cached JWKS.
  3. Verify with that key.

Key rotation playbook

PhaseJWKS containsSigner uses
t=0oldold
t=1old + newold
t=2old + newnew
t=3 (after max-token-age)newnew

Never hard-cutover. Old tokens issued under the previous kid must still verify until they expire.

Cache, but refresh on miss

JWKS responses can be cached for hours (typical: 1h, max-age comes from the HTTP Cache-Control). But if you receive a JWT with an unknown kid, refresh immediately — the auth provider rotated and you missed it.

Symmetric vs asymmetric

HS256 secrets MUST stay secret, so HS256 keys are never published in a JWKS. JWKS is for asymmetric public keys (RS256, ES256, EdDSA). We model an HS256 registry here for simplicity, but the lookup protocol is identical.

kid injection: a footgun

A naive verifier does:

python

kid="../../etc/passwd" reads /etc/passwd. Always treat kid as untrusted input — restrict to [a-zA-Z0-9_-]+, or use it as a dict key, never a path.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…

JWKS: Key Set + kid Lookup — Build a JWT Library