Free online JWT decoder
JWT decoder that explains the claims
Paste a JSON Web Token and it is split on the two dots, Base64url-decoded and pretty-printed in front of you — free, no signup, and no key needed, because reading a token requires nothing but the token. Every registered claim is translated: exp, iat and nbf become UTC and local dates with a countdown that ticks, and an expired token, a missing exp or an alg of none is called out above the panels instead of being left for you to spot. Decoding is not verification, and the token is decoded by JavaScript in this tab and sent nowhere — which matters, because the token you are about to paste probably still works.
- 100% free
- No signup
- Never leaves your tab
- Expiry countdown
- alg: none flagged
Nothing is sent anywhere: the token is split and decoded by JavaScript in this tab.
How to decode a JWT
Paste, read the three segments, and check the dates — no key and no account involved.
Paste the token
Drop the whole string in, prefix and all: a leading “Authorization:”, a “Bearer”, surrounding quotes and the line breaks a terminal wrapped into it are stripped before anything is decoded. The clipboard shortcut works outside the box too — ⌘V on a Mac, Ctrl+V elsewhere — so there is nothing to click first, and the two sample buttons load a working token and an alg: none token if you only want to see what the output looks like.
Read the three segments
The header and payload panels show the decoded JSON indented two spaces, with an optional A–Z key sort that makes two tokens from the same issuer comparable line by line. Under the input the token is repeated with each segment in its own colour, so you can see where the header ends, where the payload ends, and how much of the string is signature.
Check the claim table and the flags
The table lists every claim in the payload with its value, a sentence on what it is for, and — for exp, nbf, iat and auth_time — the raw epoch number, the UTC instant, your local time and how long ago or how far ahead it is. Anything worth acting on appears as a coloured flag above the panels: expired, not valid yet, no exp at all, a date sent as a string, milliseconds where seconds belong, a duplicated claim, or alg: none.
Technical specifications
| Token format | Compact JWS serialisation — three Base64url segments joined by two dots. A five-segment JWE is recognised and named, but its payload is encrypted and no decoder can open it without the key. |
|---|---|
| Base64url handling | URL-safe alphabet with - and _, missing = padding restored automatically, and the standard + / alphabet decoded anyway with a warning that it is not a valid JWT |
| Text encoding | Strict UTF-8 — accented names and emoji in a payload come out intact, and bytes that are not valid UTF-8 are reported instead of being shown as mojibake |
| Claims explained | iss, sub, aud, exp, nbf, iat and jti from RFC 7519, plus azp, nonce, scope, scp, client_id, auth_time and act, and alg, typ, kid, cty, crit, jku, jwk, x5t, x5u, enc and zip in the header |
| Date display | The raw epoch value, ISO 8601 in UTC, your local time with its zone abbreviation, and a relative countdown that reticks every second |
| Algorithms recognised | HS256/384/512, RS256/384/512, PS256/384/512, ES256/384/512, EdDSA and none — each with the signature length it produces, checked against the segment you pasted |
| Signature | Displayed and measured in bytes, never verified: 32 bytes for HS256, 64 for ES256, 256 for RS256 with a 2048-bit key, 0 for none |
| Maximum token size | 1 MB, far past the 8 KB of request headers most servers accept and the 4 KB a cookie can hold |
| Price and processing | Free with no signup and no run limit; the token is decoded in this browser tab and is never sent to a server or written to storage |
Frequently asked questions
Can this JWT decoder verify the signature?
No, and that is deliberate. Verifying needs the issuer's secret for HS256 or its public key for RS256 and ES256, and a web page that asks you to paste a signing secret next to a live token is asking for the one value that should never leave your own infrastructure. Verify where the key already lives instead — jose or jsonwebtoken in Node, PyJWT in Python, golang-jwt in Go — and pin the algorithm there rather than reading it out of the token.
Why does my token decode fine here but get rejected by the server?
Decoding only proves the token is well-formed; six further checks stand between that and acceptance. Roughly in order of how often they fire: exp has passed, aud does not contain the verifier's own identifier, iss is not the issuer it expects, the alg in the header is not the algorithm it pinned, kid names a key that has rotated out of the JWKS, and the signature does not match because the token came from a different environment. A NumericDate sent as a JSON string rather than a number is the seventh, and this page flags that one for you.
What does alg: none mean?
It means the token carries no signature at all. RFC 7519 §6 defines an unsecured JWS whose third segment is empty, meant for tokens already protected some other way — wrapped in a JWE, or carried over mutual TLS. It became notorious in 2015, when several libraries would verify an alg: none token against a configured key and return success, so an attacker could take a genuine token, rewrite the payload, drop the signature and be admitted as anyone. The fix is on the verifier: accept a fixed list of algorithms decided in your own code, never the one the header asks for.
Is it safe to paste a production token into a JWT decoder?
On this page the token stays in your tab, split and decoded by JavaScript that was already downloaded, with nothing sent anywhere and nothing kept after you close it. That is not true of every decoder, and a JWT is a bearer credential: whoever holds it is the user until it expires. Check where the decoding happens before you paste, and treat a token you have pasted into a tool you do not control as spent — revoke it or let it expire rather than assuming nobody kept a copy.
Can I change a claim and get a working token back?
No — editing the payload breaks the signature, and only the issuer can produce a new one. The third segment is an HMAC or a digital signature computed over the first two, so a single altered character in the payload gives a token that fails verification everywhere it is checked. To test a different set of claims, mint a fresh token from your own issuer or from a local key, which is a two-line script in any JWT library.
What is the exp claim, and how do I read a number like 2051222400?
exp is a NumericDate — seconds, not milliseconds, since 1970-01-01 UTC — after which the token must be rejected. 2051222400 works out to 2035-01-01T00:00:00Z, which this page shows beside the raw number along with the same instant in your own time zone. The classic bug is passing Date.now() straight into the claim: that is milliseconds, so the token expires roughly 56,000 years from now, and any date claim above 100,000,000,000 gets flagged here for exactly that reason. Verifiers typically allow about 60 seconds of clock skew either side.
Why does my token have five segments instead of three?
Five segments means a JWE, an encrypted token rather than a signed one. The parts are the protected header, an encrypted content key, an initialisation vector, the ciphertext and an authentication tag, and only that first header is readable without the decryption key. No browser tool can show you the claims inside one; you have to decrypt it where the private key lives. This page recognises the shape and says so rather than printing nonsense.
About decoding JSON Web Tokens
A JWT is not encrypted, and that is the most misread thing about the format. Its three segments are Base64url — an encoding with no key and no secret anywhere in it, picked over standard Base64 only because - and _ survive a URL and a cookie where + and / do not, which is why a plain Base64 decoder can read a payload segment once you swap the two characters back. Anyone holding the token can read every claim in it, so the payload is the wrong home for a password, a national ID or anything else you would not put in a log line. What the signature buys is integrity, not confidentiality: it proves the claims have not changed since the issuer wrote them, and nothing else.
Nearly every JWT vulnerability of the last decade has been an attack on the header rather than on the cryptography. alg: none was the first — libraries read the algorithm out of the token and did as they were told, so deleting the signature was enough. RS256-to-HS256 confusion was the second: take the service’s public key, which is public by definition, and use its bytes as an HMAC secret, and a verifier that trusts the header will check the HMAC with the very same bytes and pass. The kid parameter supplies the third, being attacker-controlled text that some implementations drop straight into a file path or a SQL query. All three have the same defence: decide the algorithm and the key set in your own configuration, and treat the header as a claim you compare against rather than an instruction you follow.
Day to day, the time claims cause more confusion than the cryptography. exp, nbf and iat are NumericDate values counted in seconds, so a claim that looks a thousand times too large is a Date.now() that never got divided; if you have a bare epoch number and want it the other way round, the epoch converter goes both directions. iat is not auth_time — the second is when the person actually authenticated and can be hours earlier. aud is allowed to be either a string or an array of strings, and code that handles only one shape breaks the day a second audience is added. And nbf catches people out more often than exp: a token minted on a machine whose clock runs two minutes fast is invalid for two minutes everywhere else, which presents as an intermittent login bug rather than as a clock problem.
Where your token is decoded
The token never leaves this tab. Splitting it on the dots, decoding the Base64url and parsing the JSON all happen in JavaScript that was downloaded with the page, so no request carries the token to a server, nothing is written to localStorage, and no analytics event sees it — open your browser’s network panel and watch nothing happen while you paste. Navigate away and the decoded claims go with the page.
One habit is worth keeping anyway: a JWT is a bearer credential, so any token you have pasted into a tool you do not control should be treated as spent, and revoked or rotated rather than trusted.