JWKS Decoder
What Is a JWKS?
A JSON Web Key Set is a JSON document containing an array of public keys, published so that anyone verifying a token can fetch the key that signed it. Identity providers serve one at a well-known URL — commonly https://issuer.example.com/.well-known/jwks.json — and it is the mechanism that makes token verification work at scale without distributing keys by hand.
Each entry is a JSON Web Key: a JSON object describing one key's type, intended use, and the raw mathematical parameters. For RSA that means a modulus n and a public exponent e; for elliptic curve keys it means a curve name and the point coordinates x and y. All of these are base64url-encoded big-endian integers, which is why a JWK looks like an opaque wall of characters until something decodes it.
Why a Key Set Holds Several Keys
A key set contains more than one key so the issuer can rotate signing keys without breaking tokens already in circulation. During a rotation the issuer publishes the new public key alongside the old one, starts signing with the new key, and removes the old one only after every token signed with it has expired. Consumers that re-fetch the key set keep verifying throughout.
The kid field is what makes this work. It labels each key, and every token signed by that key carries the same kid in its header, so a verifier knows exactly which key to use rather than guessing by trial. A key set whose entries lack kid values forces verifiers to attempt every key in turn — this tool flags that, because it is a design smell rather than a fatal error.
The Fields You Will See
| Field | Meaning |
|---|---|
| kty | Key type — RSA, EC, OKP (Edwards curves), or oct (symmetric) |
| kid | Key identifier, matched against the kid in a token header |
| use | sig for signature verification, enc for encryption |
| alg | The algorithm this key is intended for, such as RS256 or ES256 |
| n / e | RSA modulus and public exponent. AQAB decodes to 65537, the near-universal exponent |
| crv / x / y | Elliptic curve name and public point coordinates |
| x5c | An X.509 certificate chain, if the issuer publishes one |
| d, p, q | Private parameters. These must never appear in a published key set |
d, treat the key as compromised. The d parameter is the private exponent. A JWKS is a public document, so a private parameter appearing in one means the signing key has been published to anyone who requested the URL. This tool raises a warning when it sees private material, but the only real remedy is to rotate the key immediately.
Converting a JWK to PEM
Most command-line tooling — OpenSSL, and the majority of server-side libraries outside the JavaScript ecosystem — expects a PEM-encoded key rather than a JWK. This tool performs that conversion by importing the JWK through the Web Crypto API and exporting it in SPKI form, which is the structure inside a BEGIN PUBLIC KEY block. Because the browser's own cryptographic implementation does the encoding, the output is the same DER structure OpenSSL would produce.
Note the distinction between key formats that look similar. BEGIN PUBLIC KEY is SPKI and carries an algorithm identifier alongside the key material. BEGIN RSA PUBLIC KEY is PKCS#1 and holds only the RSA numbers. Libraries are usually specific about which they accept, and supplying the wrong one produces an unhelpful parse error rather than a clear message.
Key Thumbprints (RFC 7638)
A JWK thumbprint is a SHA-256 hash over a canonical form of the key containing only its required members, sorted lexicographically with no whitespace. It gives a key a stable identifier derived from the key material itself, so the same key produces the same thumbprint regardless of which optional fields a particular system attaches to it.
This is genuinely useful when tracking a key across environments. If staging and production disagree about whether a token should verify, comparing thumbprints answers "is this actually the same key?" without eyeballing a 2048-bit modulus. Some issuers also use the thumbprint as the kid value, which makes key identity self-describing.
Reading RSA Key Strength
The modulus length reported here is derived from the decoded byte length of n. A 2048-bit modulus is the current baseline for RSA signing keys, and 3072 or 4096 bits are common where a longer protection horizon is wanted. Keys below 2048 bits are flagged: 1024-bit RSA is deprecated and should not appear in a key set serving production traffic.
Elliptic curve keys achieve comparable strength with far smaller parameters, which is why ES256 signatures are a fraction of the size of RS256 signatures. If token size matters — and it does when every request carries one in a header — EC keys are worth considering. One naming trap is worth remembering: ES512 uses curve P-521, not a curve called P-512.
Debugging a Failing Verification
When a token that should verify does not, work through the key set in this order:
- Does the token's
kidexist in the key set? If not, the issuer has rotated keys and your cached copy is stale. This is by far the most common cause. Our JWT decoder shows the headerkidwithout needing any key. - Does
ktymatch the token's algorithm? AnRS256token needs an RSA key; anES256token needs an EC key. A mismatch means you are holding the wrong key set entirely. - Is
useset tosig? A key published for encryption will not verify signatures, and a key set may legitimately contain both. - Is the curve right? An EC key on P-384 cannot verify an ES256 signature, which is defined over P-256.
- Once the key looks right, confirm the signature itself with our JWT signature verifier, which takes this key set directly and selects the key by
kid.
Caching a Key Set Sensibly
Fetching the JWKS on every request is wasteful and makes your service depend on the issuer's availability for every single call. Fetching it once at startup is worse, because the next key rotation breaks you until a redeploy. The workable pattern is to cache the key set with a modest time-to-live, and additionally re-fetch when a token arrives bearing an unknown kid — with a rate limit on that refresh, so a stream of malformed tokens cannot turn into a fetch storm against the issuer.