JWK/JWKS Inspector & JWT Signature Debugger
Inspect JWKS keys, match JWTs by kid, verify signatures locally with Web Crypto, and diagnose exactly why token validation fails.
Your tokens and keys stay private. JWT parsing and cryptographic signature verification happen locally in your browser using the Web Crypto API — no tokens, keys, or secrets are sent to CodeAva servers. JWKS URL fetches use a lightweight server-side fetch layer for CORS reliability, but the JWT itself never leaves your browser.
JWT parsing and cryptographic signature verification run entirely in your browser using the Web Crypto API. No tokens, JWKS payloads, or secrets are sent to CodeAva servers. JWKS URL fetches use a lightweight server-side fetch layer for CORS reliability — the JWT itself is never transmitted.
Overview
A JSON Web Key (JWK) is a JSON representation of a cryptographic key. A JSON Web Key Set (JWKS) is a collection of JWKs, typically published at a well-known URL by identity providers like Auth0, Okta, Google, AWS Cognito, and Firebase. When a service issues JWTs signed with an asymmetric algorithm like RS256 or ES256, it uses a private key to sign the token and publishes the matching public key in its JWKS so that consuming applications can verify the signature without access to the private key.
Verifying a JWT against a JWKS requires more than just fetching the keys. The token header carries a kid (key ID) claim that identifies which specific key in the set was used for signing. The verifier must find the key with the matching kid, confirm the algorithm is compatible, and then perform the cryptographic signature check. When this fails — and it commonly does during key rotation, environment mismatches, or configuration errors — the error messages from libraries are often minimal and hard to debug without visibility into the key material and token header.
This tool provides that visibility. Paste or fetch a JWKS and a JWT, and it shows exactly which key was selected, whether the signature is valid, and — if not — a clear diagnosis of why: missing kid, algorithm mismatch, expired token, audience mismatch, wrong environment, or a genuinely invalid signature. All cryptographic operations use the browser's native Web Crypto API — nothing is sent to a server.
Use cases
When to use it
- Debugging Auth0, Okta, Cognito, or Firebase token failurespaste the JWT from the failing request and the JWKS from your identity provider to verify the signature and inspect claim values in one view.
- Diagnosing kid rotation issueswhen an identity provider rotates keys, tokens signed with the old key will fail if the new JWKS no longer includes it. The tool shows exactly which kid was in the token and which kids are in the JWKS.
- Distinguishing cryptographic failures from claim failuresa signature can be valid while the token is still unusable because it is expired, has the wrong audience, or came from the wrong issuer. This tool shows both categories separately.
- Converting keys between PEM and JWKuse the PEM ↔ JWK converter to translate a PEM public key from a certificate or config file into a JWK for use in a JWKS, or convert a JWK back to PEM for a library that expects PEM format.
- Testing with the wrong environment's JWKSa common mistake is using a production JWKS to verify a staging token or vice versa. The kid mismatch diagnostic surfaces this immediately.
When it's not enough
- Encrypted JWTs (JWE)this tool handles signed JWS tokens (3-part). Encrypted JWTs (5-part JWE) require private key decryption and are out of scope for v1. Use a server-side JOSE library to decrypt JWEs.
- Authorization decisions in productionthis is a debugging tool. Never use it to authorize access — always verify tokens server-side with a trusted library in your application's runtime.
- Algorithms not yet supportedcurrent support: RS256/384/512, ES256/384/512, HS256/384/512. EdDSA (Ed25519/Ed448) and PS256/384/512 (RSASSA-PSS) are not supported in v1.
How to use it
- 1
Load your JWKS or JWK
Choose Paste to paste a JWKS JSON or single JWK, JWKS URL to fetch a live endpoint, or OIDC Issuer to auto-discover the jwks_uri from the OpenID Connect discovery document. The server-side fetch handles CORS so the request always works regardless of the provider's CORS policy.
- 2
Paste your JWT
Paste the signed JWT token (3 dot-separated parts) and click Parse JWT. The header and payload are decoded locally in your browser. The token is never sent to any server.
- 3
Optionally set expected values
Enter expected issuer (iss), expected audience (aud), or expected algorithm to get richer diagnostics. For HMAC tokens (HS256/HS384/HS512), enter the shared secret.
- 4
Click Verify Signature
The tool matches the kid from the JWT header to the JWKS, checks algorithm compatibility, and runs the signature verification using the Web Crypto API.
- 5
Review diagnostics and claims
The Verification tab shows the cryptographic result and diagnostic messages. The Claims tab shows all payload claims with exp/nbf/iss/aud validation results if expected values were provided.
Common errors and fixes
kid not found in JWKS
The JWT was signed with a key that is no longer in the JWKS. Common causes: key rotation (the old key was removed before all tokens expired), wrong environment JWKS (staging vs production), or the JWKS URL is cached and stale. Refetch the JWKS and check whether the kid in the JWT header matches any key in the set.
Algorithm mismatch between JWT and key
The alg in the JWT header does not match the alg declared in the matched key. Verify that the identity provider configuration and the application's expected algorithm are in sync. RS256 and ES256 are not interchangeable — they use different key types (RSA vs EC).
Signature invalid
The signature did not verify against the selected key. Possible causes: the token was tampered with, you are using the wrong key or JWKS, the JWT was signed by a different service, or the algorithm parameters do not match. Check that the JWKS URL matches the issuer in the JWT's iss claim.
Token is expired
The exp claim is in the past. For debugging purposes, this is expected if you are testing with an old token. In production, ensure your token refresh logic works before tokens expire. Check clock drift if tokens expire immediately after being issued.
Audience mismatch
The aud claim in the token does not match the audience you expect. Make sure the token was requested with the correct audience parameter for your application. Different Auth0/Okta APIs often issue tokens with different audience values.
5-part token detected (JWE)
This token is an encrypted JWT, not a signed JWT. Encrypted JWTs require the private key to decrypt. Use a server-side library like jose (Node.js) or your platform's equivalent to decrypt and inspect a JWE.
PEM to JWK conversion fails
Ensure the PEM is complete and unmodified, including the BEGIN/END header lines. PKCS#1 RSA keys (BEGIN RSA PUBLIC KEY) may need to be converted to SPKI format (BEGIN PUBLIC KEY) first using openssl rsa -pubout. EC keys must use a supported curve (P-256, P-384, P-521).
Frequently asked questions
Related
What is a JWKS and why is it used for JWT verification?
A JWKS (JSON Web Key Set) is a JSON document containing a collection of public keys. It is the standard mechanism identity providers use to publish the keys that applications should use to verify JWT signatures. The JWKS is typically hosted at a well-known URL — for example https://your-issuer.com/.well-known/jwks.json — and can be discovered automatically through the OIDC discovery document at /.well-known/openid-configuration.
In an asymmetric JWT flow (RS256, ES256, etc.), the identity provider signs the token with a private key that it holds exclusively. The matching public key is published in the JWKS. A verifying application reads the kid from the JWT header, finds the key with the matching kid in the JWKS, and uses it to verify the signature. No secret needs to be shared — the private key never leaves the identity provider.
Identity providers rotate JWKS keys periodically. Applications should cache the JWKS with a reasonable TTL and re-fetch it on kid cache-miss rather than on every request. If a token arrives with a kid that is not in the cached JWKS, the application should fetch the JWKS once more before failing — the key may have been rotated and the cache may be stale.
JWT signature verification troubleshooting guide
| Symptom | Likely cause | Practical fix |
|---|---|---|
| kid not found | Key rotation, wrong environment JWKS, or stale JWKS cache | Re-fetch JWKS. Confirm the issuer URL matches the token's iss claim. Check staging vs production endpoints. |
| alg mismatch | Token uses RS256 but JWKS key declares ES256, or vice versa | Align the algorithm in the identity provider config and the verifier's expected algorithm. RS256 and ES256 use different key types. |
| Signature invalid | Wrong JWKS, tampered token, or wrong key selected | Verify the JWKS URL matches the issuer. Check that the correct key is selected. Confirm the token has not been modified. |
| Token expired | exp claim is in the past | Use a fresh token. For debugging, check clock drift. In production, verify token refresh logic runs before expiry. |
| Token not yet valid | nbf claim is in the future | Check system clock. nbf is sometimes set a few seconds ahead to account for clock skew between services. |
| Audience mismatch | Token aud does not match the expected audience for this API | Request the token with the correct audience parameter. Different APIs on the same IdP often have different audience values. |
| Issuer mismatch | Token iss does not match what the application expects | Confirm the application is configured with the right issuer URL. Staging and production environments often have different issuer values. |
| Wrong environment key | Production token verified against staging JWKS or vice versa | Use the JWKS URL from the same environment as the issuer in the token's iss claim. |
Node.js JWT verification with JWKS
The jose library is the recommended modern approach for JWKS-backed JWT verification in Node.js. It handles JWKS fetching, caching, and kid matching automatically.
import { createRemoteJWKSet, jwtVerify } from "jose";
const JWKS = createRemoteJWKSet(
new URL("https://your-issuer.com/.well-known/jwks.json")
);
// Call this per incoming request — jose caches the JWKS internally.
const { payload, protectedHeader } = await jwtVerify(token, JWKS, {
issuer: "https://your-issuer.com",
audience: "https://your-api.com",
});
// payload is the verified claims object.
// Never trust payload before this call returns successfully.JWKS caching note: jose's createRemoteJWKSet caches the fetched keys in memory and re-fetches on kid cache-miss. For high-volume services, consider a shared cache layer so that key-rotation fetches do not spike per-instance. Never disable caching entirely — re-fetching the JWKS on every request is a denial-of-service risk against your identity provider.