JWT Decoder
Decode any JWT into header, payload and a plain-language claims table — expiry checked live, zero third-party code on this page.
Header
The decoded header appears here.
Payload
The decoded payload appears here.
Signature
No signature segment in this input.Signature not checked — this tool only decodes. Verify signatures with the JWT Verifier (coming soon), or with your server-side library today.
Claims
Registered claims appear here once a token decodes.
Press ? for shortcuts · Never stored — a token is a credential. This page keeps nothing between visits.
This page loads no third-party code — no ads, no trackers, no analytics. Verify in your Network tab.
Do it offline:$ python3 -c 'import sys,base64,json; s=sys.argv[1].split(".")[1]; print(json.dumps(json.loads(base64.urlsafe_b64decode(s+"="*(-len(s)%4))), indent=2))' "$JWT"
How to use it
- Paste the token — from a cookie, an Authorization header, a curl command, wherever it was living. Framing such as a Bearer prefix, wrapping quotes or a stray line break is stripped and declared as a chip; decoding runs as you type.
- Read the three labeled sections: the header pane names the algorithm and token type, the payload pane carries the claims as pretty-printed JSON with numbers kept verbatim, and the signature section reports the byte length. Each pane has its own named copy button.
- Work the claims table beside the panes: every registered claim present is translated into plain language, and exp, nbf and iat appear in local time, in UTC and as a relative reading, with a one-second countdown feeding the status chip.
- Copy the payload, download header and payload as one .json file, or share a link. Sharing defaults to the built-in sample token; folding your own token into a link requires confirming a warning that names the risk. Clear and Sample are undoable.
Paste a JSON Web Token and its header, payload and signature unfold instantly: pretty-printed JSON panes, a claims table that turns iss, sub, aud, exp, nbf, iat and jti into plain language, and a live countdown settling the verdict — EXPIRED, NOT YET VALID or ACTIVE. Everything happens in your browser: this page ships zero third-party code, and the token is neither stored nor sent anywhere.
How it works
A JWT in its everyday form is a JWS in compact serialization (RFC 7515 §7.1): three segments separated by dots, each written in base64url — the URL-safe alphabet of RFC 4648 §5, with - and _ standing in for + and /, padding omitted. The first segment encodes a small JSON header naming the signing algorithm and token type; the second, the JSON claims; the third, the signature's raw bytes. Splitting on dots and reversing the base64url step is the whole of decoding — hence no key is ever asked for here.
The signature is computed over exactly the first two segments as they appear on the wire — encoded header, dot, encoded payload (RFC 7515 §5.1). It covers every claim, so a verified token cannot have been altered undetected; and it covers nothing else, so the framing around a token — quotes, a Bearer prefix, whitespace — can change freely. What a signature never does is hide content: signing proves origin and integrity, not confidentiality.
Decoding and verifying are different acts. Decoding is reading: base64url reversed, JSON pretty-printed, no secret consulted, no integrity checked — a tampered token decodes exactly as happily as a genuine one, as the third example below demonstrates. Verifying means recomputing the signature with the right key, and that is deliberately out of scope here; a permanent line under the panes says so. RFC 8725 exists because that gap keeps producing real vulnerabilities — alg: none acceptance and algorithm confusion are its headline items, and this page flags both patterns.
The time claims — exp, nbf and iat — are NumericDates (RFC 7519 §2): seconds, never milliseconds, since 1970-01-01T00:00:00Z, leap seconds ignored. The claims table renders each one in local time, UTC and relative form, and the countdown ticks once per second against your machine's clock. Treat the chip as advisory: the verdict that matters is your server's, after verification, usually with the small clock-skew leeway RFC 7519 §4.1.4 permits.
Examples
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFkYSBMb3ZlbGFjZSIsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNTE2MjQyNjIyfQ.dB2E3DiNV7qdnWYi4TVE8FZ3LRFmCgVlvVNg82YiC9c{
"sub": "1234567890",
"name": "Ada Lovelace",
"iat": 1516239022,
"exp": 1516242622
}Pasted exactly as it left an Authorization header — the Bearer prefix is stripped and declared as a chip, never silently. The header reads alg HS256, typ JWT; the signature is 32 bytes, the HMAC-SHA-256 output size. The time claims frame a one-hour life: issued 01:30:22 UTC, expired 02:30:22 UTC on 2018-01-18 — so the chip settles on EXPIRED at once.
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ik1hbGxvcnkiLCJhZG1pbiI6dHJ1ZX0.{
"sub": "1234567890",
"name": "Mallory",
"admin": true
}A well-formed unsecured token: alg is none and the third segment empty, the trailing dot still required. It decodes like any other — precisely the danger — so the page answers with a red banner: “This token is unsigned (alg: none) — never accept it server-side.” Notice what the forger did with the freedom: an admin flag, and no exp to ever end it.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFkYSBEb3ZlbGFjZSIsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNTE2MjQyNjIyfQ.dB2E3DiNV7qdnWYi4TVE8FZ3LRFmCgVlvVNg82YiC9c{
"sub": "1234567890",
"name": "Ada Dovelace",
"iat": 1516239022,
"exp": 1516242622
}The sample token with one payload character changed — position 44, M swapped for E — decodes without a murmur, to a different name. Only signature verification catches the edit, and only a holder of the key can perform it. One much-cited community rule fits, and this page agrees: “Don't do anything with any token that you wouldn't do with one that granted access to real resources or contained PII.”
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZGExIiwiYXVkIjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vdjE/cGFnZT0yIiwiaWF0IjoxNTE2MjM5MDIyfQ.dB2E3DiNV7qdnWYi4TVE8FZ3LRFmCgVlvVNg82YiC9c{
"sub": "ada1",
"aud": "https://api.example.com/v1?page=2",
"iat": 1516239022
}Minted by an encoder that never learned base64url: the payload segment carries a / where RFC 7515 requires _. Pasted as-is, decoding stops with “Invalid base64url: character `/` at position 64 of the payload segment — that is the standard Base64 alphabet ('+' and '/'); decode again with standard Base64 accepted.” The offered one-click rerun does exactly that, with a chip recording the translation. This header also writes its fields in the opposite order: JSON key order carries no meaning.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
A 13-digit exp is a milliseconds bug, not a long life
exp, nbf and iat count seconds since the Unix epoch — ten digits for any date in this century. An issuer reading a milliseconds clock and forgetting to divide emits 13 digits, dating the token tens of thousands of years out. Time claims past a trillion earn a chip naming that suspicion; the decoded JSON keeps the number as written.
cty: JWT — there is a token inside the token
When one JWT wraps another — signed, then signed again by another party — the outer header carries cty: JWT and the outer payload is not JSON but the inner token's compact form. Nothing fails silently: the pane shows the raw text with a not-JSON notice, and a one-click offer decodes the inner token in place, undoably.
An empty middle segment can be deliberate
RFC 7515 Appendix F allows detached payloads: the token travels as header..signature while the payload takes another channel, so two consecutive dots are not automatically damage. The header still decodes, the signature length still reports, and a chip explains the form — paste the payload back between the dots to inspect it whole.
Count the dots: two segments and five tell different stories
Two segments is either an unsecured token missing its trailing dot or, far more often, a paste that lost its tail; the banner asks which, and both surviving parts still decode best-effort. Five segments is a JWE — genuinely encrypted, its claims unreadable without the key. Only the JWE protected header renders here, said plainly instead of failing.
Tokens past 8 KB start dying in transit
JWTs ride in headers and cookies, and default header ceilings sit near 8 KB across common proxies and servers. A size chip appears at that mark — a token that large usually means claim sprawl or an embedded certificate chain — and input past 64 KB is declined outright: at that size the paste has stopped being a token.
Nothing on this page persists — deliberately
A pasted token is a live credential more often than anyone intends, so this tool opts out of every convenience that would write it anywhere: no restore-on-return buffer, no opt-in draft saving, nothing kept but a display preference. Leave the page and the token is gone. Links carrying your own token are minted only after a confirmed warning.
Common errors
Invalid base64url: character `\` at position 11 of the payload segment — base64url uses only A–Z, a–z, 0–9, '-' and '_'; remove it or re-copy the token.- The named character sits in the payload segment at the counted position — here a literal backslash, the tell of a token copied out of a JSON log with an escaped line break still embedded. The decoder stops rather than guessing, names the segment, and leaves the paste untouched while you remove the stray.
Input is larger than the 64 KB limit for this tool. For bigger payloads use the CLI: python3 -c 'import sys,base64,json; s=sys.argv[1].split(".")[1]; print(json.dumps(json.loads(base64.urlsafe_b64decode(s+"="*(-len(s)%4))), indent=2))' "$JWT"- Genuine tokens live far below this cap, so an over-limit paste is nearly always a whole log line, a request dump or a file. The page declines the entire input rather than truncating — a shortened token would decode to confidently wrong claims — and the Python line keeps oversized material on your own machine.
Two segments — unsecured JWT or truncated paste? A signed JWT has three dot-separated segments.- One dot is missing, along with everything after it. Usually the signature was lost in transit: a terminal cut the line, a chat client swallowed the tail, a regex matched too little. Both surviving segments still decode beneath the banner; if the source genuinely mints unsecured tokens, the well-formed spelling ends with a trailing dot and says alg: none.
FAQ
Can I decode a JWT without knowing the secret?
Yes — that surprise is the lesson. Header and payload travel as base64url, an encoding anyone can reverse; the secret participates only in producing and checking the signature segment. Decoding needs no key and proves nothing about authenticity. It also means every claim is public to whoever holds the token — never put anything in a payload you would not print in a log line.
Why does the token still decode after I change a character?
Because decoding never consults the signature. Alter a payload character and base64url still reverses, the JSON still parses — the third example above executes exactly that edit. What breaks is verification: the signature covers the original bytes, so a verifier holding the key rejects the tampered token. If an edited token still passes your server, it is not verifying — treat that as an incident.
How do I check when a JWT expires?
Paste it and read the exp row of the claims table: the moment in local time and UTC, a relative reading with a live countdown, and the chip settling on EXPIRED, NOT YET VALID or ACTIVE. Two caveats belong to the claim itself: a 13-digit exp is almost always a milliseconds bug, flagged here; and verifiers allow a small clock-skew leeway, so a token seconds past exp may still be accepted by design.
What are registered claims?
The seven payload names RFC 7519 §4.1 reserves with fixed meanings: iss, who minted the token; sub, whom it is about; aud, who should accept it; exp, nbf and iat, the validity window and mint time; jti, a unique identifier for replay detection. All are optional. Anything else is a claim the issuer chose — kept visible in the payload pane and counted, not guessed at.
Is a JWT encrypted?
The three-segment tokens this page reads are not. They are JWS — signed, not encrypted — and base64url is an encoding, not a cipher; producing readable claims without any key is exactly what this page is doing. Encrypted tokens exist: a JWE has five segments, and only its header is readable keyless. If a claim would embarrass you on a billboard, use a JWE or keep the data server-side.
Why does this page carry no ads?
Because the input is a credential. A decoder that loads advertising scripts asks you to paste bearer tokens into a page running other people's code — the category's most-quoted complaint. The answer here is verifiable, not rhetorical: zero third-party requests, checkable in your browser's Network tab in ten seconds. Prefer expendable test tokens even so.
What does alg: none actually mean?
An unsecured JWT: the header declares no signature and the third segment is empty. RFC 7519 defines the form for closed systems where integrity arrives another way, and RFC 8725 directs verifiers to refuse it absent explicit opt-in — the historical bypass was libraries honoring none from a forged header. This page decodes such tokens under a red banner, treating None and NONE identically: creative casing was part of the exploit.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Run the decode again right now — reassurance on a tool that is already live as you type.
- ⌘/Ctrl + S
- Download header and payload as one .json file — on this page it downloads rather than saving the page, as the help overlay warns.
- ⌘/Ctrl + C
- Copy the decoded payload JSON while focus is in the tool and nothing is selected; a real selection copies just itself.
- ⌘/Ctrl + Shift + C
- Copy the decoded payload JSON regardless of what is selected.
- t
- Step to the next color theme (ignored while typing, mid-IME composition, or when single-key shortcuts are off).
- ? or ⌘/Ctrl + /
- Open the shortcuts overlay, where the browser-shortcut conflicts worth knowing about are spelled out.
- Esc
- Close the topmost dialog. The token input is never cleared.