A JWT looks like line noise with two dots in it. It is actually three separate things joined together, and two of them are plain readable JSON wearing a thin disguise.
The three parts
Split on the dots and you get header, payload and signature.
The header says which algorithm signed the token — usually HS256 or RS256 — and that it is
a JWT. The payload holds the claims: who the user is, what they may do, when the token expires.
The signature is a cryptographic check over the first two parts.
The first two are base64url-encoded, not encrypted. Anyone holding the token can decode and read them, with no key and no permission. That is not a flaw; it is the design.
The consequence people miss
Never put a secret in a JWT payload. Not an API key, not a password hash, not internal data you would not show the user. Signing proves a token has not been altered. It does nothing to hide what is in it.
This trips up teams regularly, because “signed” sounds like “sealed”. It isn’t. A JWT is a tamper- evident envelope with a transparent window.
Reading the claims that matter
Several claims are conventional and worth knowing on sight. sub is the subject — usually the user
ID. iss is who issued it. aud is who it is meant for. jti is a unique token ID.
The three that cause the most confusion are timestamps: exp (expiry), iat (issued at) and nbf
(not valid before). All three are seconds since 1970, not milliseconds — a frequent source of
bugs, since JavaScript’s Date.now() returns milliseconds and mixing them up puts your expiry
either in 1970 or somewhere around the year 56000.
Our decoder converts them to real dates and flags whether the token has actually expired, which is usually the question you opened it to answer. You can also convert timestamps directly.
Why we refuse to verify signatures
Plenty of online JWT tools offer signature verification. To do that they need your signing secret — the HMAC key, or the private key for RSA.
Think about what that request is. A website is asking you to paste the credential that lets anyone mint valid tokens for your system, into a text box, on a server you know nothing about. If that key leaks, an attacker can forge a token claiming to be any user with any permissions, and your backend will accept it as genuine.
There is no version of that which is a good idea, and we deliberately do not offer it. Decoding tells you what a token claims. Only your own backend, holding the key, can tell you whether those claims are trustworthy.
Treat tokens as live credentials
A JWT is usually a bearer token: whoever holds it can act as the user it describes until it expires. Pasting one into a random website is closer to pasting a password than most people assume — it may end up in an access log, an error tracker, or an analytics payload.
That is why our decoder runs entirely in your browser. The token is never transmitted, and the page is served with a Content Security Policy that prevents it from being sent even if the code tried.