JWT Decoder
Decode a JWT header and payload. Optionally verify HS256/RS256 signatures — all client-side.
Privacy: The token never leaves your browser. Decoding is base64url plus JSON.parse in this tab, and the optional HS256/384/512 check runs through the Web Crypto API locally — neither the token nor the secret is sent to a server or logged. The one caveat you control: if you use the shareable link, the token is in the URL, so treat that link as being as sensitive as the token itself. The secret is never written to the URL.
Decoding happens entirely in this tab. The token is never uploaded, and a JWT payload is only base64url — it is readable by anyone who has the token, signed or not.
What it does
Paste a JWT and get the header and payload pretty-printed, every registered claim explained in plain English, the timestamps converted to real dates with a verdict on whether the token is currently valid, and a list of the things about the header that should worry you. If the algorithm is HS256, HS384, or HS512 you can also paste the shared secret and check the signature.
A leading Bearer is stripped, so you can paste straight from an
Authorization header. Five-part tokens are recognised as JWE and reported as
such rather than failing with a confusing parse error.
How it works
Everything runs in the tab. The three dot-separated segments are base64url —
that is + and / swapped for - and _ with the padding dropped, per
RFC 7515 Appendix C.
Decoding is atob on a re-padded string, then TextDecoder and JSON.parse.
No network request is made and nothing is stored.
Signature verification uses the Web Crypto
API:
the secret is imported as a raw HMAC key and crypto.subtle.verify compares the
signature against the signing input, which is the first two segments joined by a
dot — the exact bytes off the wire, not a re-serialisation. That matters, because
JSON does not round-trip byte-for-byte, and verifying a re-encoded payload would
produce false failures.
What the warnings are actually about
The header is where JWT implementations get broken, and the tool flags four things.
alg: none means the token is unsigned. A verifier that reads the algorithm out
of the token’s own header and honours none accepts anything.
RFC 8725 §3.2 — the
JWT Best Current Practices document — says reject it outright.
Any HS* algorithm draws a warning for the algorithm-confusion attack. HMAC uses
one key for both signing and verifying; RSA and ECDSA use a private key to sign
and a public key to verify. If your service publishes an RS256 public key and the
verifier picks its algorithm from the header, an attacker takes that public key,
re-signs a forged payload as HS256 using the key material as the HMAC secret, and
your verifier happily validates it. The fix is one line: pin the expected
algorithm in your verification call instead of trusting the token.
jku and jwk headers tell the verifier where to find the key, or hand it the
key directly. Trusting either lets the token choose the key that validates it,
which is the same failure in a different costume —
RFC 8725 §3.8 covers
it.
A crit header lists extensions the verifier must understand. If it does not
understand one, the correct behaviour is to reject the token, not to skip it.
On the payload side the most common real-world bug is time units.
RFC 7519 §2 defines
NumericDate as seconds since the Unix epoch, but Date.now() returns
milliseconds. A token signed with Date.now() + 3600000 expires roughly 48000
years from now and every verifier accepts it forever. Anything above 1e11 gets
flagged. A missing exp gets flagged too: without it the token is valid until
your server-side revocation list says otherwise, and most deployments do not have
one.
When to reach for it
Reach for it when a request is coming back 401 and you need to know whether the
token expired, whether the aud matches what the API expects, or whether the
iss is the environment you think it is. Reach for it when you are handed a
token from a system you do not own and want to see what identity and scopes it
actually asserts. Reach for it when a signature check fails locally and you want
to confirm whether the secret is wrong or the token is corrupted — a valid decode
with a failed HMAC narrows that down immediately.
Do not use it as a verifier for anything that matters. A green result here means the bytes match a secret you pasted; it does not check the issuer, the audience, the clock skew policy, or your revocation list. Real verification belongs in a library, server-side, with the algorithm pinned.
And remember what a decoded payload proves: nothing about confidentiality. A JWS payload is encoded, not encrypted. Anyone who intercepts the token reads every claim in it.
Related tools
- Base64 encoder/decoder for the encoding underneath each segment.
- Hash generator to compute the HMAC yourself and compare.
- HTTP header inspector to see what an endpoint returns when the token is rejected.
- Password strength checker for the secret behind an HS256 key.
- Unix timestamp converter for the raw NumericDate values.
Frequently asked questions
Is it safe to paste a production token here?+
Why can I read the payload without a key?+
What is wrong with alg=none?+
none will accept any payload an attacker cares to write, which is a complete authentication bypass. RFC 8725 §3.2 says to reject it. The general rule: the algorithm is a property of your key, decided by your configuration — not a field the token gets to choose.Why does the tool only verify HMAC signatures?+
/.well-known/ endpoint and selecting a key by kid. Doing that here would mean making network requests on your behalf, which defeats the point of a browser-only tool. For those algorithms, verify server-side with a library that pins both the expected algorithm and the key source.The exp claim looks like a date far in the future. What happened?+
Date.now() in JavaScript returns milliseconds. Signing with Date.now() + 3600000 instead of Math.floor(Date.now()/1000) + 3600 produces a token that expires in the year 50000. The tool flags any time claim above 1e11 for this reason.Related tools
Base64 Encoder/Decoder
Encode and decode Base64 in your browser, with correct UTF-8 handling, a URL-safe alphabet toggle, and file mode for binary payloads.
Hash Generator
CRC32, MD5, SHA-1, SHA-256, SHA-384, SHA-512 and HMAC over text or a local file. Hex or base64 output, computed in your browser.
HTTP Header Inspector
Paste a URL, see the response headers with a plain-English explanation of each.
→ Read the full guide:How this tool actually works