Decode a JSON Web Token to read its header and claims, and check the expiry, without pasting it into a website that might log it.
A JWT is three base64url segments separated by dots, and the first two are merely encoded — not encrypted. Anyone holding the token can read its claims, which is worth knowing before putting anything private in one. Decoding it is how you find out why a request was rejected: an expired exp, an audience that does not match, an issuer you did not expect.
This page decodes the header and payload, renders exp, iat and nbf as readable dates alongside the raw epoch numbers, and says plainly whether the token has expired. It does not verify the signature, because doing so needs the issuer’s key — and a decoder that claimed to have checked a signature it could not check would be worse than one that does not try.
The alg field in the header is where the historical vulnerabilities live, and reading it is the quickest sanity check on a token. Servers once accepted alg: none and skipped verification entirely because the token told them to. The algorithm-confusion attack works by re-signing an RS256 token as HS256, using the issuer public key as the HMAC secret — a key the attacker already has, because it is public. Both are fixed on the server side by deciding in advance which algorithm will be accepted rather than reading the answer out of the very token being checked. Seeing the header in plain text is how you notice that a token has arrived signed with something other than what you expected.
The registered claims are a short list and each fails in its own way. exp and nbf bound the validity window, iat records when the token was issued, iss and aud say who made it and who it was meant for, and sub identifies the subject. Every time value is in seconds rather than milliseconds, so a token whose exp was written in milliseconds appears to expire tens of thousands of years from now — a mistake this page makes visible immediately by rendering the date next to the raw number. Small clock differences between the issuing and the verifying machine are the other routine cause of a token rejected as expired, or as not yet valid, a few seconds either side of when it should be.
A JWT cannot be withdrawn, and that is a design consequence rather than an oversight. The entire point is that a server can validate one without asking anybody, which also means nothing can tell that server the token has been revoked before exp elapses. Logging a user out everywhere therefore needs a denylist, or short lifetimes plus refresh tokens — either of which puts back the server-side state the token was supposed to remove. Size is the quieter constraint: a token travelling in a header is attached to every single request, and the 8 KB header limit common to web servers is reachable once roles and permissions are packed into the claims.
The kid field in the header exists because issuers rotate their signing keys. It names which key was used, so a verifier holding several can pick the right one instead of trying each in turn, and an issuer can publish a new key and retire the old one without invalidating tokens already in circulation. A token whose kid is absent from the issuer current key set is usually old rather than forged. Seeing the value here is how you check that a token was signed with the key you expect before going looking for a verification bug that is not there.
No. Decoding is base64url and JSON parsing performed locally in your browser. Even so, treat a production token as a live credential.
No. Verification needs the signing key, which should never leave your server. Use your backend library for that.
Most often a truncated copy, or a leading "Bearer " that was included by accident. A JWT must have exactly three segments separated by dots.