JWT decoder
Decode a JSON Web Token’s header and payload, expand standard claims, and flag alg:none and expired tokens.
What this does
A JSON Web Token is three base64url-encoded segments joined by dots:
header.payload.signature. This tool splits the token, decodes
the header and payload to readable JSON, and explains the registered
claims — iss, sub, aud,
exp, nbf, iat, jti —
converting the numeric timestamps to readable UTC. It then runs a few
safety checks and, for HMAC tokens, can verify the signature if you supply
the secret.
All of this happens in your browser. You can paste a live session token from your own application to see exactly what your auth server put in it.
Reading the signature segment
The third segment is a signature or a MAC over
base64url(header) + "." + base64url(payload). The
alg field in the header says how it was produced:
- HS256 / HS384 / HS512 — HMAC with a shared secret. The same secret both signs and verifies, so it must never be shipped to a browser or a third party.
- RS256 / PS256 / ES256 — asymmetric. The issuer signs with a private key; anyone can verify with the public key. This is what you want when the verifier and the signer are different parties.
- none — no signature at all. Treat its presence on an auth token as a bug or an attack.
Decoding never checks the signature by itself. A JWT you pulled from a log is just as decodable whether or not it was tampered with — the decoded payload tells you what someone claims, not what is true. Only signature verification against the correct key makes it trustworthy.
Why <code>alg: none</code> and algorithm confusion matter
Two classic JWT vulnerabilities both come from trusting the token to tell
you how to verify it. The first is alg: none: if your library
honours it, an attacker strips the signature, edits the payload, and walks
in. The second is RS256-to-HS256 confusion: the server
expects an RS256 token and verifies with the RSA public key, which is not
secret. An attacker changes the header to HS256 and signs the
token using that public key's bytes as the HMAC secret. A naïve verifier
that reads alg from the token then "verifies" the forgery.
The fix for both is the same: the verifier decides the algorithm and the
key out of band, and rejects any token whose header disagrees.
Worked example
Load the sample token. The header is
{"alg":"HS256","typ":"JWT"} and the payload includes
"iss":"auth.example.com", "aud":"api",
"exp":1700003600, and "role":"admin". The claims
table converts exp to a UTC time and explains that
aud must equal your service's identifier or the token should
be rejected. Because that sample exp is in the past, the
status line reports the token as expired. Enter any secret in the verify
field and the tool reports the signature does not match — the sample
signature is illustrative, not real.
Limits and gotchas
- No asymmetric verification. RS/PS/ES signatures can't be checked here without the issuer's public key; only HS256/384/512 are supported.
- Clock skew. The expired / not-yet-valid checks use your device clock. Real verifiers usually allow a small leeway (30–60 seconds).
- Decoding is not validation. A well-formed token can still be forged, revoked, or issued by the wrong party.
- Encrypted tokens (JWE) have five segments and are not decodable without the key; this tool handles signed tokens (JWS) only.
- Sensitive payloads. Anything in the payload is readable by anyone who holds the token. Don't put secrets in claims.
Frequently asked questions
- Does decoding a JWT here reveal it to anyone?
- No. The token is split and base64url-decoded in your browser with JavaScript. Nothing — not the token, not the payload, not a secret you enter for verification — is sent to a server. That is the point of doing it client-side: you can safely inspect a real production token.
- Why is "alg": "none" dangerous?
- A JWT with
alg: nonehas no signature. The standard allows it for cases where the token's integrity is guaranteed by other means, but if an application accepts it on a normal auth path, an attacker can craft any payload they like —admin: true, someone else's user ID — and it will be trusted. Several real libraries historically acceptednoneby default. Your verification code must pin the expected algorithm and reject anything else, includingnone. - The payload looks fine but is the token actually valid?
- Decoding only proves the token is well-formed. A token is valid only if the signature verifies against the issuer's key and the claims check out:
expin the future,nbfin the past,issis who you expect, andaudcontains your service. This tool checks the time-based claims and can verify an HMAC signature; it cannot verify RS/ES/PS signatures because it doesn't have the issuer's public key. - What is the difference between the "alg none" warning and an expired warning?
- "alg none" is a structural red flag about how the token is signed — it should almost never appear on a real token. "Expired" means the token was legitimately issued but its
exptimestamp has passed, so a correct server will now reject it. Both cause the status line to turn amber, but they are different problems: one is a possible attack, the other is normal token lifecycle.