JWT decoder
Decode a JSON Web Token to inspect its header and payload. Decoding happens locally — your token is never sent anywhere.
{
"alg": "HS256",
"typ": "JWT"
}{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}What this JWT decoder does
Paste a JSON Web Token and the tool splits it on the dots, Base64URL-decodes
the first two parts and pretty-prints them as JSON. The header tells you the
signing algorithm and token type, the payload holds the claims, and if an
exp claim is present you get a human-readable UTC expiry line above them.
The signature is not checked — this is a reading tool for debugging auth
flows, not a validator. Everything runs locally; the token is never
transmitted.
How to use it
- Paste the token into the Token box. Whitespace around it is ignored; the sample is the well-known HS256 example from jwt.io.
- The Header and Payload panels update as you type.
- If the payload has an
expclaim, an Expires … line appears with the date in ISO 8601 (UTC). Compare it with now to see whether the token is still valid. - Use Copy on either panel to grab the formatted JSON.
If you see “Could not decode token”, the input is not a JWT (many session cookies and API keys are opaque strings, not JWTs) or a character was corrupted in transit.
Anatomy of a JWT
A signed JWT (JWS) is three Base64URL strings joined by dots:
header.payload.signature.
| Part | Content | Example (decoded) |
|---|---|---|
| Header | Algorithm and type, sometimes a key ID | {"alg":"HS256","typ":"JWT","kid":"2024-01"} |
| Payload | The claims — registered, public and private | {"sub":"1234567890","name":"John Doe","iat":1516239022} |
| Signature | HMAC or digital signature over header.payload | 32 raw bytes for HS256, shown as 43 Base64URL characters |
Base64URL is standard Base64 with + and / replaced by - and _ and the
trailing = padding removed, so a token survives inside URLs and HTTP headers
without further encoding. A five-part token (four dots) is a JWE, an encrypted
JWT — its payload cannot be read without the key, and this tool will not
decode it.
Standard claims to look for
| Claim | Meaning | Format |
|---|---|---|
iss | Issuer — who minted the token | String or URL, e.g. https://accounts.example.com |
sub | Subject — the user or principal | String, typically a user ID |
aud | Audience — who should accept it | String or array of strings |
exp | Expiration time | Unix seconds (not milliseconds) |
nbf | Not valid before | Unix seconds |
iat | Issued at | Unix seconds |
jti | Unique token ID, used for revocation lists | String |
Timestamps are seconds, so 1516239022 is 2018-01-18T01:30:22Z. If a value
looks ten times too long (13 digits) somebody serialized milliseconds, and
most libraries will treat the token as valid for thousands of years. Use the
timestamp converter to check any claim beyond
exp.
Decoding is not verifying
The payload you see is exactly what a server would see before checking the
signature — and that is the point of the signature. Reading "role":"admin" in
a token says nothing about whether the token is trusted. A proper check on the
server does all of the following:
- Verify the signature with the expected key and the algorithm you expect, never the one in the header.
- Reject if
expis in the past ornbfis in the future (allow a small clock skew, usually 30–60 s). - Check
issandaudmatch your service. - Optionally check
jtiagainst a revocation list.
Skipping step 1 or trusting the header’s alg is how most real-world JWT
vulnerabilities happened. Algorithms you will typically meet: HS256 (shared
secret, symmetric), RS256 (RSA public/private key), ES256 (ECDSA P-256),
EdDSA (Ed25519).
Related tools and snippets
- Base64 encoder / decoder — decode a single token part by hand, or inspect Base64 data elsewhere in an auth flow.
- Timestamp converter — turn
iat,nbfand other Unix-second claims into readable dates. - JSON formatter & validator — format larger claim payloads or validate JSON you plan to put in a token.
- Hash generator — SHA-256 is the hash under HS256 and RS256; see what a digest looks like.
- UUID generator — a common choice for the
jticlaim.
FAQ
Does this verify the signature?
No. Decoding only reads the Base64URL-encoded header and payload; verifying requires the server's secret (HS256) or public key (RS256/ES256) and must happen on the server. A token that decodes fine can still be forged or expired.
Is it safe to paste my token here?
Yes. Decoding runs entirely in your browser with no network request, so the token never leaves the page. Still, treat access tokens like passwords and avoid pasting production tokens into tools that send them to a server.
Why can anyone read my JWT payload?
Because a JWS token is signed, not encrypted. The payload is plain JSON in Base64URL, which is why you should never put passwords, card numbers or secrets in claims. If you need confidentiality, use JWE (encrypted JWT) or keep the data server-side.
What does the "Expires" line mean?
It converts the exp claim (seconds since the Unix epoch) to an ISO 8601 UTC timestamp. Compare it with the current time — if it is in the past the token is expired. If the payload has no exp claim the line is not shown.
Why does it say it could not decode the token?
Either the parts are not valid Base64URL (a character got mangled while copying, or you pasted an opaque session ID that is not a JWT) or the decoded part is not JSON. Make sure you pasted the whole token with its two dots.
What is the alg none attack?
Some libraries once accepted tokens whose header said "alg":"none" and skipped signature checks entirely. Always pin the expected algorithm on the server and reject any other value, no matter what the header claims.