Cryonel

"JWKS Key Not Found" / kid Mismatch, Explained

This means the token's header points at a key that isn't (or is no longer) in the identity provider's published key set — a different failure mode from a bad signature or an expired token.

What triggers it

A JWT signed with RS256/ES256 etc. carries a kid (key ID) in its header identifying which public key to verify it against:

{
  "alg": "RS256",
  "kid": "2024-03-key-1",
  "typ": "JWT"
}

The verifier fetches the identity provider's JWKS (usually at /.well-known/jwks.json) and looks for an entry with a matching kid. If none exists, verification fails before the signature is even checked — there's no key to check it against.

Why this usually means key rotation

Identity providers rotate signing keys periodically for security, publishing a new key and eventually retiring the old one from the JWKS. If a token was signed with a key that's since been retired — or if your app cached an old JWKS and hasn't refreshed it — you'll see exactly this error. It's rarely a sign of a forged token; it's almost always a caching or timing issue.

How to debug it

  1. Decode the token's header (without verifying) in the JWT Decoder to read its kid.
  2. Fetch the current JWKS from the provider's /.well-known/jwks.json endpoint and paste it into the JWKS Inspector to list every kid currently published.
  3. If the token's kid isn't in that list, the token was signed with a retired key — it needs to be re-issued, not "fixed."
  4. If your application caches the JWKS, make sure it refreshes periodically (most JWT libraries support this) rather than fetching it once at startup.

Related Tools