What this tool does
This JWT decoder splits a token into its three parts, decodes the header and the payload, and explains every claim it finds. Timestamps become readable UTC dates with the distance from your own clock, so you can see at a glance whether a token has expired, when it was issued and how long its lifetime is.
It runs entirely in the page. That matters more here than on most tools: the tokens people need to inspect are usually real ones, taken from a failing request in staging or from a customer's browser, and every claim inside is readable by anyone who holds it. Pasting one into a service that keeps logs is a disclosure. Nothing here is transmitted.
How to use it
- Paste the token. A
Bearerprefix copied from anAuthorizationheader is fine — it is stripped. - Read the status line: valid, expired, or not yet usable.
- Work down the claim list for what each field means.
- Copy the payload as JSON if you need it in a bug report.
The three parts
A JWT is three base64url segments joined by full stops: header.payload.signature.
The header says how the token was signed. alg names the algorithm, typ is almost always
JWT, and kid tells a verifier which of the issuer's keys to use.
The payload is a JSON object of claims. Seven are registered by RFC 7519 — iss, sub, aud,
exp, nbf, iat, jti — and everything else is whatever the issuer decided to put there.
The signature is a MAC or a digital signature over the first two parts. It is the only part that provides any security, and it is the part this page does not touch.
Base64url is used rather than standard Base64 because the token travels in URLs and headers, where
+ and / are hostile. If you want to see the same encoding in isolation, the
Base64 encoder and decoder has a URL-safe mode.
Decoding is not validating
This is the distinction that produces the worst bugs in this area, so it is worth stating plainly.
Decoding reverses an encoding. It needs no key, proves nothing, and anyone can do it — this page does it, your browser's console does it, an attacker who intercepts the token does it. A decoded payload tells you what the token says.
Validating checks the signature against a key you trust, then checks exp, nbf, iss and
aud against what you expect. It is the only thing that turns what the token says into something
you may act on.
Code that decodes a JWT and trusts a claim from it has no authentication at all. It is a
surprisingly common shape: a front end reads sub from the token to decide what to display, which
is harmless, and then a back end does the same to decide what to return, which is not.
alg: none, and why the header is not to be trusted
The specification defines none as a valid algorithm for unsecured tokens. Combined with a
verifier that reads alg from the header to decide how to check the signature, this produces the
classic attack: an attacker rewrites the payload, sets alg to none, drops the signature, and a
naive implementation accepts it. A related version swaps RS256 for HS256 so the public key gets
used as an HMAC secret.
The lesson is structural. The header is supplied by whoever sent the token, so it cannot be allowed
to choose the verification rules. A correct verifier decides in advance which algorithms it accepts
and rejects everything else. This page flags alg: none when it sees it, because a token that
carries it in the wild is either a test fixture or an attack.
What exp really buys you
exp limits the blast radius of a leaked token and nothing more. It is not revocation: between
issue and expiry, a stolen token works. That is why short lifetimes plus refresh tokens are the
common pattern, and why a token with no exp at all — which this page will tell you about — is a
permanent credential in everything but name.
Two operational details show up constantly here. The claims are seconds since 1970, and a generator that passes milliseconds is out by a factor of a thousand — a 2026 date arrives as the year 57971 — which this page makes obvious rather than subtle. And a token that looks expired by a couple of minutes is usually clock skew between two machines, which is why libraries offer a leeway setting instead of exact comparison.