Developer Tools

JWT decoder

Paste a JSON Web Token to read its header and payload. Registered claims such as exp, iat and nbf become dates you can actually read, with how far away they are. Decoding happens in this tab — the token is not sent anywhere.

Paste a token above to decode it.

The signature is never checked here, and it cannot be. This page reads the two base64url segments and prints what is inside. It has no key, so it cannot tell you whether a token is genuine or whether a character of the payload has been altered. Only the service holding the signing key can verify a token, on the server that trusts it.

Header

Nothing decoded yet.

Payload

Nothing decoded yet.

Signature

Encoded signature
Algorithm claimed
Verified?No — nothing here verifies anything.

Your token stays in this tab. It is not uploaded, logged or stored — no cookie, no local storage, no history. Close the tab and it is gone.

How the decoding works

A JWT is three chunks joined by full stops: header, payload, signature. The first two are JSON objects in base64url — ordinary base64 with + and / swapped for - and _ so the value survives a URL, and the trailing = padding dropped. This page undoes both changes, hands the result to atob, then decodes the bytes as UTF-8 so accented and CJK text come back correctly rather than as mojibake, and runs JSON.parse.

Registered claims get help. exp, iat, nbf and auth_time are Unix seconds, unreadable at a glance, so each becomes a UTC date with the gap in words — expired 3 days ago, in 12 minutes. iss, sub, aud and jti print as they are, since the issuer defines them. Anything else appears underneath in the order it was written.

The status line compares exp and nbf against your device's clock and says Expired, Not yet valid or Valid window — a statement about two numbers, nothing more. Malformed input is named rather than swallowed: two segments instead of three, five segments (an encrypted JWE, unreadable without the key), a segment that is not base64url, a segment that is base64url but not a JSON object. Each gets its own message, and the tables clear so you never read a stale result beside an error.

About pasting real tokens into websites

The decode here is plain JavaScript operating on the string in the box, and no request leaves the page carrying your token. You do not have to take that on trust: open the Network panel, clear it, paste a token, and watch — nothing goes out with it.

The habit is still worth breaking. A JWT is usually a bearer credential, so whoever holds it can act as you until it expires. Most online decoders are also client-side, but you cannot tell by looking, and the ones that are not now have your production token in a server log. Treat pasting one into any website the way you treat pasting a password.

Questions people ask

Does decoding a JWT prove that it is genuine?

No, and this is the single most common misunderstanding about the format. Decoding is just base64 in reverse — anyone can do it to any token, including one somebody typed out by hand. The signature is what binds the header and payload to an issuer, and checking it needs the secret or the public key. A decoder without a key can tell you what a token says about itself and nothing about whether that is true. Treat everything on this page as a claim, never as a fact.

Is it safe to paste a token into an online JWT decoder?

It depends entirely on where the decoding happens, and the page cannot prove it to you in words. Check instead: open developer tools, go to the Network panel, and paste. If a request fires when you paste, your token is now on somebody's server. On this page nothing fires. Even so, prefer a token you can afford to leak — a development token, an expired one, or one you generated for the purpose. A live production token is a live credential, and the safest habit is that it never touches a text box on the public internet.

Why can anyone read the payload — is a JWT not encrypted?

A signed JWT (a JWS, which is what almost everyone means) is encoded, not encrypted. Base64url exists to make the bytes safe to put in a URL or a header, not to hide them. The design assumes the payload is readable and only guarantees that it has not been altered. So never put anything in a JWT you would not print on a postcard: no passwords, no card numbers, no internal identifiers you would rather not publish. If the contents genuinely must be secret there is JWE, the encrypted variant with five segments — and nobody can decode one of those without the key, including this page.

What is the "alg: none" trick, and does it still work?

The JWT specification allows an alg value of none, meaning an unsigned token with an empty signature segment. Early libraries would read the header, see none, and accept the token as valid — so an attacker could take a real token, rewrite the payload, set alg to none, drop the signature and walk in. A related trick swaps RS256 for HS256 so the public key gets used as an HMAC secret. Both are patched in maintained libraries, and both come back the moment code trusts the algorithm named in the header. Verify with the algorithm you expect, chosen by your code, not by the token.

My token has expired but the API still accepts it — why?

Usually clock skew. Most verifiers allow a leeway window, commonly 30 to 60 seconds, so a token that has just passed exp is still accepted. Beyond that, check whether the API is validating exp at all — it is optional in the specification, and plenty of services only check the signature. Also worth ruling out: a reverse proxy or gateway caching an authorisation decision, a refresh token quietly issuing a new access token behind the scenes, or your machine's clock drifting. The verdict on this page uses your device's clock with no leeway at all.