Decode a token
Paste the full token, all three parts joined by dots. A leading Bearer word and surrounding quotes are stripped for you.
Paste a token to start.
Header
Payload
Signature
Claims in plain English
| Claim | Value | Meaning |
|---|
Security checks
Verify an HS signature (optional)
This check is for test secrets only. It recomputes the HMAC over the original header and payload segments in your browser and compares it with the token signature. It checks the signature only, not expiry, audience, or issuer.
Never paste a production secret or a private key into any web page. If a production secret was pasted somewhere it should not be, rotate it. RS256, ES256, and other public key tokens cannot be verified here, because this page does not take public keys.
How to read a token
A signed JWT has three base64url segments joined by dots: header, payload, and signature. The decoder above splits on the dots and decodes the first two segments as JSON. The third segment stays as raw text, because a signature is bytes, not JSON.
| Part | What it holds | Example |
|---|---|---|
| Header | The token type and the signing algorithm. | {"alg": "HS256", "typ": "JWT"} |
| Payload | The claims: who the token is for, who issued it, and when it expires. | {"sub": "1234567890", "name": "John Doe", "iat": 1516239022} |
| Signature | The HMAC or digital signature over the header and payload, computed with a key. | SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c |
Base64url is an encoding, not encryption. The payload looks scrambled, but anyone holding the token can reverse it in seconds. That is why a token must be treated like a password, and why secrets never belong in a payload.
Registered claims
RFC 7519 defines seven registered claims. None of them is required by the spec, so a token may carry only some of them. Custom claims sit next to them, and this decoder lists those too, with the note that their meaning comes from the issuer, not the spec.
| Claim | Meaning | Watch for |
|---|---|---|
iss | Issuer: who minted the token. | A token from an issuer your service does not trust. |
sub | Subject: who the token is about, usually a user id. | A subject that does not match the account making the request. |
aud | Audience: who the token is meant for. | A token minted for another service, replayed against yours. |
exp | Expiry: seconds since 1970-01-01 UTC, after which the token must not be accepted. | A missing exp claim, which means the token states no expiry of its own. |
nbf | Not before: the earliest time the token becomes valid. | A token used before its nbf time, often a clock skew problem. |
iat | Issued at: when the token was minted, in the same seconds format. | An iat time far in the future, which points at a wrong clock. |
jti | JWT id: a unique id for this token, used to track or revoke single tokens. | A reused jti, which can mean a replayed token. |
Time claims use seconds, not milliseconds. A value like 1893456000 means 2030-01-01 in UTC. A 13 digit value is almost always milliseconds by mistake, and the decoder flags values that fall far outside a sane range.
Decoding is not verifying
Decoding answers what a token says. Verifying answers whether to believe it. A full server side check does three things in order: verify the signature with a key the server trusts, check the time window from exp and nbf, and check that iss and aud match what the service expects. A valid signature alone is not enough, and a readable payload alone proves nothing.
Two failure modes show up most often. First, a verifier that trusts the token header to pick the algorithm can be talked into alg none, or into checking an RS256 token with HS256 using the public key as the secret. The fix is to pin one expected algorithm per key on the server, never from the header. Second, a short or dictionary word HS256 secret can be brute forced offline from one captured token, after which an attacker mints valid tokens at will. Long random secrets, or an asymmetric algorithm, close that hole.
Decode in code
In Node.js, the payload is one line, with no library needed:
JSON.parse(Buffer.from(token.split('.')[1], 'base64url').toString())
In the browser, the same decode needs a base64url to base64 step first, then a UTF-8 safe decode, so names with accents survive. The decoder on this page does exactly that, and it never sends the token anywhere to do it.
Frequently asked questions
Is a JWT encrypted?
No. A normal signed JWT is signed, not encrypted. The header and payload are only base64url encoded, so anyone holding the token can decode and read them. The signature proves the token was not changed and came from the key holder. It does not hide the contents. To hide contents, use an encrypted JWT (JWE), which has five parts instead of three.
Does decoding a token prove it is valid?
No. Decoding only reads the token. A token can decode cleanly and still be forged, expired, or issued for someone else. Trust needs two more steps: verify the signature with the issuer key, then check the claims your service cares about, such as expiry, audience, and issuer.
Can this page verify RS256 tokens?
No. This page verifies HMAC signatures only (HS256, HS384, HS512) with a shared secret. RS256, ES256, and similar tokens need the signer public key, and this page does not take public keys. Verify those tokens on your server or with a verifier that accepts a public key.
Why does my token say expired when login just worked?
Check which token you pasted. Login flows often hand out two tokens: a short lived access token and a longer lived refresh token. If you pasted the access token after it expired, the app may already have swapped it for a fresh one. Also check the clock on the machine that minted the token, and confirm the exp claim is in seconds, not milliseconds.
What does alg none mean?
It means the token carries no signature. A verifier that accepts alg none trusts any token anyone mints. A correct verifier picks the expected algorithm on the server side and rejects alg none outright, instead of trusting the header.
Is it safe to paste a production token here?
Decoding on this page runs entirely in your browser, and the token is never sent to a server. Even so, prefer a test token or an expired token for debugging. A live token is a working credential until it expires, so do not paste one into any page you do not trust, and rotate it if it was exposed.
Sources
- jwt.io, JSON Web Token Introduction: https://www.jwt.io/introduction (what a JWT is, when to use one, and the header, payload, and signature structure).
- Stytch, A developer guide to RFC 7519, part 1: JWT structure and claims: https://stytch.com/blog/rfc-7519-jwt-part-1/ (registered claims, base64url encoding, and the HMAC signature formula).
RFC 7519 defines the token format and the registered claims. RFC 7515 defines the JSON Web Signature format that signed tokens use, and RFC 7518 defines the algorithms, including HS256, RS256, and ES256. This page is an independent implementation, not affiliated with jwt.io, Stytch, or any token library.
Agents
Machine readable summary for AI assistants: