A JSON Web Token looks like an opaque string, but two of its three parts are plain JSON with a base64url coat on. This decoder takes them off, prints the header and payload, and reads the registered claims back in ordinary language — when the token was issued, when it stops being valid, and who it was issued to.
Decoding is not verifying
It is worth being blunt about this, because a lot of tools blur it. Decoding a token tells you what it claims. Verifying a token tells you whether those claims were written by someone holding the signing key. Only the second one is a security check, and it cannot happen here.
Verifying needs the shared secret or the public key, and pasting a production signing secret into a web page is precisely the habit that leads to a breach. Nothing on this page asks for one. A token can be expired and perfectly genuine, or unexpired and completely forged — your server, holding the key, is the only thing that can tell those apart.
- What this page can tell you — the algorithm named in the header, every claim in the payload, and whether the dates the token carries place it inside its own validity window.
- What it cannot tell you — whether the signature is real, whether the issuer is who the iss claim says, or whether the token has been revoked.
The three parts of a token
A JWT is three base64url segments joined by dots. Split on the dots and you have the whole structure.
- Header — the algorithm and token type. Usually two keys. Watch for alg: none, which means the token is unsigned and should be rejected by anything that receives it.
- Payload — the claims. Some are registered by the spec (iss, sub, aud, exp, nbf, iat, jti); the rest are whatever the issuer put there.
- Signature — raw bytes over the first two parts. Not readable text, and not checked here. A token with five parts instead of three is not a JWT at all but an encrypted JWE, which cannot be read without the key.
Seconds, not milliseconds
The exp, nbf and iat claims hold a NumericDate: seconds since 1 January 1970, not milliseconds. This trips up hand-rolled token issuers constantly, because almost every language’s "current time" function returns milliseconds.
The symptom is unmistakable once you know it. Read a millisecond value as seconds and the token expires in the year 56000; divide a second value again and it expired in January 1970. This decoder reads the claims as the spec defines them and says so plainly when a value is too large to be seconds, rather than quietly dividing by a thousand and hiding the bug.
Reading the dates
exp is exclusive: a token is expired on the exp second itself, not one second later. nbf is the opposite bound — a token is not usable before it, which is how issuers build in a grace period for clock skew between servers.
iat is informational. It says when the token was minted, which is useful for spotting a token that has been sitting in a log or a browser far longer than anyone intended, but it does not bound validity on its own.
FAQ
Is my token sent to a server?
No. The decoding happens in your browser, in JavaScript, on your device. The token is never uploaded, logged or stored anywhere, which is why a production token is safe to paste here. You can confirm it by opening your browser’s network tab, or by disconnecting from the network — the page keeps working.
Can this check whether my JWT signature is valid?
No, and that is deliberate. Verifying a signature requires the signing secret or public key. A web page that asks you to paste your signing secret is asking for the keys to every token your system will ever issue. Verify on your server, with a library, using a key that never leaves it.
Why does my token say it is expired when my application accepts it?
Most often clock skew: your machine and the issuing server disagree by a few seconds or minutes, and this page reads the clock on your device. If the gap is large, check the exp value itself — a millisecond timestamp read as seconds produces dates thousands of years in the future, and this page flags that case explicitly.
What does alg: none mean?
It means the token is unsigned. It is a legitimate part of the specification for cases where the transport itself is trusted, but it is also the basis of a classic attack: strip a token’s signature, set alg to none, and a careless verifier accepts it. Any service that receives tokens should decide which algorithms it accepts in advance and reject everything else, none included.
Can I decode an encrypted token?
Not without the key. A JWE has five dot-separated parts rather than three and its payload is ciphertext, so there is nothing to read. If your token has five parts, this page will say so rather than failing with a confusing error.