Decoding is not verifying
This is the point worth being blunt about, because the tooling encourages the confusion. A JWT in the common JWS form is three base64url segments joined by dots. Base64url is a text encoding, the same class of thing as hex — it is not encryption, has no key, and hides nothing. Anyone who obtains a token can read every claim in it with three lines of code. This page decodes and pretty-prints; that is the entire operation.
What separates a genuine token from a fabricated one is the third segment, the signature over the first two. Verifying it requires the issuer's key: the shared secret for HS256, or the matching public key for RS256 and ES256. This tool has neither. So a token whose payload someone hand-edited to say "role": "admin" will decode here, render in the same green, and look completely normal. A token that looks fine on this page can still be forged. The only thing you can conclude from a successful decode is that the base64 was well-formed and the JSON parsed.
Verification belongs in your server code, with a library that does it properly: jsonwebtoken or jose in Node, PyJWT in Python, jjwt or nimbus-jose-jwt in Java, golang-jwt in Go. Every one of them wants the key and an explicit list of accepted algorithms.
Do not paste a live token here
The decoding happens in your browser. No request carries the token anywhere, and you can confirm that with the network panel or by pulling the network cable. That is true and it is still not a reason to paste a live session token into a field on a web page.
Fields get autofilled and autosaved. Browser extensions read the DOM of every page you open. Screenshots get pasted into tickets. Form values survive a back-navigation. A bearer token is the credential — anyone holding it can act as you until it expires, with no password involved. Habits are what fail here, not this particular page. Use an expired token, a staging token, or redact the payload before pasting. If you have already pasted a production token somewhere you should not have, the fix is to invalidate the session rather than to reason about whether it leaked.
Reading the time claims
exp, iat and nbf are NumericDate values: seconds since 1970-01-01 UTC, not milliseconds. Multiplying by 1000 before handing one to a JavaScript Date is the standard off-by-a-thousand bug, and the symptom is a date in January 1970. The tool renders them as UTC alongside the difference from now.
That difference is computed against your own machine's clock, so a wrong local clock produces a wrong verdict here. Real verifiers allow a small leeway — typically 30 to 120 seconds of clock skew — before rejecting on exp or nbf, which is why a token this page calls expired by ten seconds may still be accepted by the server. An absent exp is worth noticing: nothing inside such a token ever makes it stop working, and it stays a valid credential until the issuer revokes the key or maintains a denylist.
What belongs in a payload, and what does not
Since the payload is readable by anyone holding the token, it is the wrong place for anything you would not put on a postcard. No passwords, no government identifiers, no internal notes about the user. The claims should be the minimum a resource server needs to make an authorisation decision: who the subject is, who issued it, who it is for, what scopes it carries, when it expires.
Readable does not mean modifiable, though, and that asymmetry is the actual design. Edit a claim and the signature no longer matches, so a correctly configured server rejects it. "Correctly configured" carries weight: the classic JWT vulnerabilities are servers that honoured "alg": "none" and skipped verification entirely, and servers that let an attacker downgrade RS256 to HS256 and sign with the public key as the HMAC secret. Both are fixed the same way — the verifying side pins the algorithm it will accept rather than reading it out of the attacker-supplied header. If you see none in the alg field of a token in production, that is a finding, not a curiosity.
Questions people ask
Why not add signature verification to this page?
For HS256 it would mean asking you to paste a shared secret into a web form, which is a habit worth refusing to teach regardless of where the code runs. For RS256 and ES256 it would mean fetching the issuer JWKS, which varies per provider and cannot be done generically from a static page. Verification is a server-side concern with the key material already in hand, and every mainstream JWT library does it in one call.
The token shows as expired but I am still logged in.
Usually the access token expired and a refresh token silently obtained a new one, which is exactly how short-lived access tokens are meant to work. The token in your clipboard is a snapshot of the old one. The other possibility is that your machine clock is off — check that before assuming anything about the auth flow.
What does five segments mean?
That is JWE, the encrypted flavour of the same standard, with header, encrypted key, IV, ciphertext and authentication tag. Unlike JWS, the payload really is encrypted and cannot be read without the decryption key. If you were expecting to read the claims and got five segments, the issuer chose encryption on purpose.
Non-ASCII characters in a claim look wrong. Is the token damaged?
The decoder here parses the bytes as strict UTF-8 and will throw rather than emit replacement characters, so a clean decode means the bytes were valid UTF-8. Garbled output that still parses usually means the issuer encoded with something other than UTF-8, which is non-conformant — RFC 7519 requires UTF-8. Copy the token again first, since a truncated paste is more common than a broken issuer.