JWT Decoder
Decode and verify JWTs entirely in your browser — your token never touches a server.
The sample token is signed with the secret secret — verification runs via WebCrypto, no network.
HS256 token, currently within its validity window.
Header
{
"alg": "HS256",
"typ": "JWT"
}Payload
{
"sub": "user_8472",
"name": "Ada Lovelace",
"role": "admin",
"iat": 1767225600,
"exp": 1830297600,
"iss": "https://auth.example.com"
}Claims
| Claim | Value |
|---|---|
| sub | user_8472 |
| name | Ada Lovelace |
| role | admin |
| iat | 1/1/2026, 12:00:00 AM (165d ago) |
| exp | 1/1/2028, 12:00:00 AM (in 2y) |
| iss | https://auth.example.com |
Payloads are readable by anyone — JWTs are signed, not encrypted. Never put secrets in claims.
How it works
A JSON Web Token is three base64url-encoded segments joined by dots: a header declaring the signing algorithm, a payload of JSON claims, and a signature over the first two parts. This decoder splits the token, decodes each segment with the base64url alphabet (the variant using - and _ instead of + and /, no padding), and pretty-prints the JSON. No parsing library, no server, no network traffic — the whole operation is a few string transforms running in your browser tab.
The claims table is where the practical value is. Registered claims like exp, iat and nbf are Unix timestamps, which are unreadable at a glance; here they are humanized into your local time with a relative description, and an expired token gets an explicit warning rather than a number you have to mentally compare against now. Issuer, subject and audience claims render as-is so you can spot a token minted for the wrong environment immediately.
Signature verification is real, not decorative. For HS256 tokens, paste the shared secret and the tool imports it as an HMAC-SHA256 key via WebCrypto's crypto.subtle, then verifies the signature over the exact header.payloadstring. A green badge means the token is authentic and untampered for that secret; a red one means the secret is wrong or the token was modified. Asymmetric algorithms like RS256 require the issuer's public key, so those tokens decode fully but are honestly labeled as not verified locally.
The prefilled sample token is signed with the literal secret secret so you can watch verification succeed, then break it: change one payload character and see the signature check fail. That exercise — observing that any modification invalidates the signature while the payload remains readable to everyone — is the fastest way to internalize what JWTs do and do not protect. They guarantee integrity and authenticity, never confidentiality — encryption of claims requires JWE, a related but distinct standard that wraps the payload in an encrypted envelope instead of merely signing it.
Frequently asked questions
Is this safer than pasting my token into jwt.io?
Yes, in the sense that nothing here ever leaves your machine. Decoding and HS256 verification both run locally — base64url decoding in plain JavaScript and HMAC verification via the WebCrypto API built into your browser. You can confirm in devtools that typing or pasting produces zero network requests. Production tokens are still credentials: prefer pasting expired or test tokens when you can.
Can it verify HS256 and RS256 signatures?
HS256 is verified fully in your browser: paste the shared secret and WebCrypto recomputes the HMAC-SHA256 over header.payload and compares it to the signature. RS256 and other asymmetric algorithms need the issuer's public key (usually fetched from a JWKS endpoint), which would require a network call — so this tool decodes RS256 tokens but marks the signature as not verified locally rather than pretending.
How should I handle exp clock skew?
The exp claim is compared against your machine's clock, and real-world clocks drift. Most server libraries accept a leeway of 30–120 seconds when validating exp and nbf. If a token shows as expired here by only a few seconds, the issuing and validating servers may still accept it — and vice versa. Always validate on the server with explicit leeway, never trust client-side clock checks for security.
What are the most common JWT bugs?
The classics: accepting alg=none tokens (always pin the expected algorithm server-side), confusing HS256 and RS256 so an attacker signs with the public key as an HMAC secret, forgetting to validate exp/nbf/iss/aud at all, and putting sensitive data in the payload — it is only base64url-encoded, not encrypted, so anyone holding the token can read every claim without the secret.
Why does the payload decode without the secret?
Because JWTs are signed, not encrypted. The header and payload are plain JSON run through base64url encoding — an alphabet tweak of base64, not cryptography. The secret only protects integrity via the signature: it proves the token was not modified, it does not hide the contents. If you need confidentiality, you want JWE (encrypted JWTs) or simply not putting secrets in claims.
Built by FORG — AI cost observability for agentic coding. Free tools, no signup, nothing leaves your browser.
Learn about FORG