Free Online JWT Decoder with Signature Verification
Decode any JSON Web Token to read its header, payload, and signature. Verify HMAC (HS256/384/512) with a shared secret, or RSA and ECDSA (RS256, RS384, RS512, PS256, ES256, ES384, ES512) by pasting a PEM public key or JWKS. Includes a built-in security audit, token size check, a side-by-side compare mode, and a sign mode for creating test tokens.
Try this example
You are debugging a 401 Unauthorized response from an API and want to know whether the JWT being sent is expired, malformed, or signed with the wrong secret.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
- 1Copy the Authorization header value from your browser DevTools (everything after "Bearer ").
- 2Paste it into the token box. The tool immediately decodes the header and payload.
- 3Look at the Time claims section. If exp shows in red with "Expired X minutes ago", the token expired and you need a fresh one.
- 4If exp is fine, paste your HMAC secret (HS256 only) into the verification box. Invalid signature means the token was issued by a different server or the secret rotated.
- 5For RS256 tokens, switch to the PEM key, JWKS URL, or JWKS JSON source and verification runs in the browser. Production code should still validate on the server as a defense-in-depth measure.
What a JWT actually is
A JSON Web Token is three base64-encoded strings joined by dots: header.payload.signature. The header says which algorithm was used to sign the token. The payload holds your claims (user ID, role, expiration, etc.). The signature lets anyone with the right key confirm the first two parts have not been tampered with.
JWT became popular for authentication because it is stateless: the server does not need to store session data. The token itself carries everything needed to identify the user. That convenience is also its biggest trade-off: once issued, a JWT cannot easily be revoked unless you maintain a denylist.
JWTs are not encrypted by default. The payload is base64-encoded, which is not encryption. Anyone who has the token can read every claim inside it. For encryption you need JWE (JSON Web Encryption), which is a separate standard.
HS256 versus RS256 and when to use each
HS256 uses HMAC-SHA256, a symmetric algorithm. Both signer and verifier share the same secret. This is simple and fast. It works well when the issuer and verifier are the same service, or when they can safely share a secret (e.g. both are your own microservices with a shared secret in Vault).
RS256 uses RSA-SHA256, an asymmetric algorithm. The signer has a private key, verifiers use the matching public key. Use RS256 when the verifier cannot be trusted with the signing key, for example when third-party apps verify tokens your service issued. The public key is typically published at a JWKS (JSON Web Key Set) endpoint.
ES256 is similar to RS256 but uses elliptic-curve cryptography instead of RSA. Signatures are smaller and verification is faster. Modern issuers (including most OpenID Connect providers) are moving toward ES256 as the default.
This tool verifies all three families (HS, RS, PS, ES) in-browser using the Web Crypto API. For RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, paste the issuer public key as PEM, or point to a JWKS URL, or paste the JWKS JSON. Only the public key is needed, never a private key. Production code should of course validate server-side too, ideally with a vetted library like jose.
The time claims: exp, nbf, iat
The exp (expiration time) claim is the most important JWT claim from a security standpoint. It is a Unix timestamp in seconds. The token must be rejected if the current time is after exp. Short-lived tokens (15-60 minutes) dramatically reduce damage from token theft.
The nbf (not before) claim is less common but useful for scheduled tokens: a token valid only starting some future time. Servers must reject tokens used before nbf.
The iat (issued at) claim records when the token was created. It is not a validity check on its own but is useful for audit trails and for computing token age. Some services reject unreasonably old iat values as an extra layer of defense.
This decoder automatically checks exp and nbf against the current time and shows the result with relative time (e.g. "expires in 23 minutes" or "expired 2 hours ago"). iat is shown for reference but not validated.
Common security mistakes
The classic JWT mistake is accepting alg:none. Some early libraries happily accepted unsigned tokens because the header said "none". Modern libraries reject this by default, but custom verification code can reintroduce the bug. This decoder flags alg:none with a red warning.
Another classic mistake is algorithm confusion: taking a token signed with RS256 and submitting it as HS256, hoping the server uses the public key as an HMAC secret. Fix: the server should enforce which algorithm is acceptable, rather than reading it from the token header.
Sensitive data in the payload is another risk. Passwords, credit-card numbers, or raw personal data should never be in a JWT payload. Anyone who intercepts the token can read them. Use the JWT only for identifiers (user ID, role) and fetch the rest from your database server-side.
For a deeper treatment of these pitfalls, see our [guide to common JWT security mistakes](/blog/jwt-security-common-pitfalls).
How to use
- 01Paste the JWT into the token box on the Decode tab. The tool accepts a raw token or the full "Bearer xxx.yyy.zzz" header value.
- 02The header, payload, and signature appear color-coded. Time claims (exp, nbf, iat) are validated against the current time, and a security audit flags missing exp, oversized tokens, sensitive claim names, and weak HMAC secrets.
- 03For HS256/HS384/HS512 tokens, paste the HMAC secret. For RS256, RS384, RS512, PS256, ES256, ES384, ES512, pick "PEM key", "JWKS URL", or "JWKS JSON" and provide the issuer public key. Verification runs automatically.
- 04Use the Sign tab to create a signed JWT from a header and payload for local testing. Use the Compare tab to diff two tokens and see exactly which claims changed.
FAQ
Can this verify RS256 or ES256 tokens?▼
Yes. Switch to RS256 or ES256 automatically based on the alg header, then provide the issuer public key in one of three ways: paste a PEM-encoded public key, paste the issuer JWKS URL and click Fetch, or paste the raw JWKS JSON. The tool uses the Web Crypto API to verify locally. RSA and ECDSA private keys are never needed for verification and this tool never asks for them.
The JWKS URL fails with a CORS error. What do I do?▼
Some issuers do not allow cross-origin fetches of their JWKS. Open the URL in a new tab, copy the JSON, then switch to the "JWKS JSON" option and paste it. Verification works the same way.
How does the tool pick the right key from a JWKS?▼
If the token header has a kid, the tool matches against that kid. If the token has no kid and the JWKS contains a single key, that key is used. If neither holds (multiple keys, no kid), you get a clear error asking to narrow the JWKS.
Why does the tool warn about alg "none"?▼
The "none" algorithm means the token is unsigned. Some libraries historically accepted "none" tokens by default, leading to severe vulnerabilities. Production systems must reject "none" outright, and this tool refuses to verify such tokens.
Is my token or secret sent anywhere?▼
No. Decoding, HMAC verification, RSA and ECDSA verification, and signing all happen in your browser using the Web Crypto API. The only network call is the optional JWKS fetch, which goes directly from your browser to the URL you provide. Open DevTools, Network tab, and confirm.
What does "Secret is base64-encoded" mean?▼
Some auth servers (notably Auth0) provide HMAC secrets in base64 form. Tick the box if your secret is base64-encoded so the tool decodes it before using it as the HMAC key.
Why does Sign mode only offer HMAC, not RS256?▼
Signing with RS256 or ES256 requires the private key. Pasting private keys into random tools is a bad habit, and browsers are not the right place to store them. Use a server-side library (node-jose, jsonwebtoken) for asymmetric signing. HMAC signing is safe here because the secret stays local and this is useful for testing.
Why are exp and nbf checked but aud and iss not?▼
Time claims have a single correct interpretation (compare against now). Audience and issuer validation depends on what your application expects, so this tool shows you the values without judging them. Always validate iss and aud server-side against your known good values.