JWT Decoder: Decode and Encode JWT Tokens

Decode a JWT as you type — header, payload, signature — and see the encoding underneath. Runs entirely in your browser.

← Back to the URL Encoder

Also searched as jwt decode · jwt token decode · decode jwt · jwt decoder · jwt parser · jwt decoder online · json web token decoder · decode bearer token. It is one tool: a JWT in, its parts out — and back again.

Everything runs in your browser. Nothing you paste is uploaded to any server — decode your token locally, not on someone else's machine.

1Decode or encode

Pick a direction, paste or edit, and the result updates live.

Direction
Paste a JWT below — it decodes as you type. A leading Bearer is ignored.
Header

—

Payload

—

Signature (base64url, not verified here)

—

2Live: the encoding underneath the token

A JWT is three base64url segments joined by dots. The readout below shows the segments, their real byte sizes, and — the part that matters — which characters standard Base64 would have written that base64url had to avoid.

Mode
Decoding
Segments
—
alg
—
Header bytes
0
Payload bytes
0
Signature bytes
0
Padding = used
none
Chars that would break in a URL
0
Token length
0
Expiry
—
Segmentbase64url (as sent)BytesStandard Base64 formWhat standard Base64 adds
Paste a JWT above to break it into its three segments.

3Why every JWT segment must be base64url

This is the part almost every JWT decoder skips. Standard Base64 uses +, / and = — and all three are meaningful characters in a URL, a query string and a cookie. A JWT is built to travel in exactly those places, so it cannot use standard Base64. It uses the URL-safe variant instead. Here is the same token in both alphabets, live.

JWT header, payload, and signature segments; the first two decode to JSON, and the signature verifies integrity rather than hiding data.
JWT segments are encoded for transport; encoding does not make their contents secret.
Your token, base64url (as sent) —
Same token in standard Base64 —
…and percent-encoded for a URL —
What that shows —
base64url (what JWT uses)Standard Base64Percent-encoding (URL)
Alphabet A–Z a–z 0–9 - _ A–Z a–z 0–9 + / not an alphabet — an escape layer on top of text
Padding usually omitted = to a multiple of 4 n/a
Safe in a query string? yes, as-is no — + reads as a space, = collides with key=value yes — that is its job
Safe in a path segment? yes no — / splits the path yes
Safe in a cookie? yes usually — but = and / are fragile unnecessary
Defined by RFC 4648 §5 (base64url) RFC 4648 §4 RFC 3986

+ in a query string is read as a space

A token with + eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.abc+dEf
Server receives abc dEf — the + became a space
Result the signature bytes differ → signature verification fails, on a token nobody tampered with
Fix use base64url (+ → -) — which is what JWT does — or %2B if you are stuck with standard Base64

/ splits a path segment

In a path /api/verify/eyJ0eXAiOiJKV1QifQ.Pj4/Pyc
Router sees two segments — Pj4 and Pyc — not one token
Result 404, or the token never arrives intact
Fix base64url (/ → _), or %2F

Trailing = padding gets trimmed or misread

Standard Base64 pads to a multiple of 4 with =
In a query string the = collides with the key=value separator; some stacks strip trailing = outright
Fix drop the padding — base64url omits it, and decoders re-add it

Why the fix is an alphabet change, not an escape

JWT could have used standard Base64 and percent-encoded every token: %2B, %2F, %3D
Why it does not the token would grow by ~5–10% at every hop, and every intermediary would have to agree to encode and decode it — one that forgets corrupts the signature
So instead RFC 7515 swaps the three offending characters for three safe ones: +→-, /→_, and drop =. Same bytes, no escaping, safe in every URL-shaped context

So does a JWT need percent-encoding in a query string or a cookie?

This is where people over-correct and break their own token. The short answer, for a token that is correctly base64url:

Query string — no. ?token=eyJhbGciOiJIUzI1NiJ9… is already valid: every character in base64url (A–Z a–z 0–9 - _) and the . separators are unreserved in RFC 3986. Nothing needs escaping.

Cookie — no. The cookie-octet set excludes whitespace, ", ,, ; and \. base64url contains none of those, so Set-Cookie: token=eyJ… is fine as-is.

Authorization header — no. Headers are not URLs. Authorization: Bearer eyJ… is sent literally; nothing is percent-decoded on the way in.

You do need percent-encoding when the JWT is not alone in the value. The four real cases:

· You are passing Bearer <token> as a query parameter — the space is not safe. ?auth=Bearer%20eyJ… (or +, but prefer %20). The token itself is still untouched.
· The token sits inside a nested URL — a redirect_uri, a next= parameter, a link in a fragment. The inner URL must be percent-encoded as a whole; the JWT inside it is then carried along untouched.
· You are handed standard Base64, not base64url — legacy systems, a JWS library configured with the standard alphabet, a signature you re-encoded yourself. Then + → %2B, / → %2F, = → %3D are mandatory, not optional.
· You are being defensive — encodeURIComponent(token) is harmless: it leaves every base64url character and the dots unchanged, so a valid JWT passes through byte-for-byte. It costs nothing but length.

Double-encoding: the trap that breaks a working token

You percent-encode the token, then it gets encoded again somewhere downstream
Result %2B → %252B — the receiver decodes once and gets the literal text %2B, not a +
Worse if you percent-encoded a base64url token and the receiver base64url-decodes it, it decodes the %XX text as if it were data — the signature no longer matches
Fix encode exactly once, at exactly one layer, and only if that layer needs it. For a base64url JWT in a query string or cookie, that layer is none

Truncating the token when you copy it

Symptom the header decodes but the payload throws, or the signature is short
Cause a base64url segment with its padding stripped has a length that is not a multiple of 4 — some tools, spreadsheets and log viewers silently trim the tail
Fix copy the whole token, and check the segment count: a JWT is always header.payload.signature

No login · Unlimited use · No watermark · Runs only in your browser. Decoding and encoding happen locally; the secret you type is never sent anywhere, and no signature is verified unless you do it yourself with the bytes shown above.

JWT Explained: Three Segments, Base64URL, and Signatures

Understand the header, payload, and signature; see why Base64URL is not encryption and why signatures must be verified.

Watch on YouTube

Related tools

Every tool on this site runs entirely in your browser. Pick the encoding problem you have:

Related troubleshooting guides