JWT Decoder
Decode JSON Web Tokens locally and verify their signature with your secret or public key — nothing leaves your browser.
Sign a token of your own to test an endpoint. Everything is computed in this page.
The key and the finished token stay in your browser; neither is sent anywhere, and neither is carried in a share link.
Verify this token in your own code. The snippet follows the algorithm in the header.
JWT Decoder - Decode a JSON Web Token Online
Paste a JSON Web Token and this decoder splits it into its three parts and shows the header and payload as readable JSON. It is the fastest way to answer the questions that come up during authentication debugging: who issued this token, who is it for, which algorithm signed it, and has it already expired?
The decoding happens entirely in your browser. That matters more here than for most tools, because a JWT is a live credential - anyone who captures a valid token can usually act as its subject until it expires. Nothing you paste on this page is uploaded, logged or stored.
What is a JSON Web Token?
A JWT is three Base64URL segments joined by dots: header.payload.signature. The header names the signing algorithm, the payload carries the claims - the facts the issuer asserts about the user or client - and the signature proves that the first two parts were produced by someone holding the key. Because the header and payload are only encoded, not encrypted, anybody can read them. Only the signature is protected.
How to decode a JWT here
- Copy the token from your
Authorization: Bearerheader, a cookie, a callback URL or your API client. - Paste the full
header.payload.signaturestring into the input field. - Click Decode to see both JSON objects laid out.
- Check
expfirst if the request was rejected, thenaudandiss.
What else this page does
The token is read as you type, so the panes fill in before you reach for the button. Under the decoded header and payload every field is listed in a table with what it is for in plain words, and a line above them turns exp and nbf into sentences: expired three days ago, expires in fifty-eight minutes, not valid yet.
- Sample loads a demo token and its secret, so you can watch a verification succeed before pasting anything of your own.
- Verify takes the secret, a PEM public key, a single JWK or a whole JWKS. Paste the document from the issuer's
/.well-known/jwks.jsonaddress and the key named by the token'skidis chosen for you, so the page still makes no request of its own. Fill in Expected issuer and Expected audience as well, and a valid signature is checked the way a server checks it: a differentiss, or anaudthat does not contain your value, turns the result red. - Build a token signs a token of your own with any of the twelve algorithms — the JWT generator page opens on it.
- Code prints the server-side verification in eight languages, following the algorithm in your token’s header.
- Two more pages open this tool pointed at a single question: has it expired and why is it being rejected.
The standard claims and what they mean
| Claim | Meaning | Why it fails |
|---|---|---|
iss | Issuer - who created the token | Mismatch when a staging token is sent to production |
sub | Subject - usually the user or service ID | Empty in tokens issued for a client rather than a person |
aud | Audience - the API meant to accept it | The single most common cause of a valid-looking 401 |
exp | Expiry as a Unix timestamp | Already in the past, or the server clock has drifted |
nbf | Not valid before this time | Token used a few seconds too early |
iat | Issued at | Used for maximum age policies and revocation windows |
jti | Unique token ID | Needed to blocklist a single token |
Decoding is not verifying
This is the point that trips people up. Reading a token tells you what it claims; it does not tell you whether those claims are genuine. Verification means recomputing the signature with the issuer's secret or public key and comparing it, plus checking expiry and audience. Any decoder can show you the payload of a forged token just as happily as a real one, so never make an authorisation decision on decoded content alone - always verify server-side with a maintained library.
Troubleshooting a token that will not work
- 401 with a valid token: compare
audwith what the API expects, andisswith the configured issuer URL. Put both into Expected issuer and Expected audience and press Verify: the result names the value the token really carries. - Expired immediately: convert
expwith the Unix timestamp converter and compare it to the server clock, not your laptop's. - Invalid segment error: the token was truncated, URL-encoded on the way, or a newline crept in during copy-paste.
- Signature verification fails: the key rotated, the wrong key ID was used, or the token was signed by a different environment.
algisnone: reject it. That value marks an unsigned token and is a classic attack against sloppy validation.
Security habits worth keeping
- Never store personal data, internal IDs or anything confidential in the payload - it is readable by design.
- Keep access tokens short-lived and use a refresh token for longer sessions.
- Transmit tokens over HTTPS only, and prefer secure, HttpOnly cookies over browser storage where you can.
- Rotate signing keys on a schedule and publish them through a JWKS endpoint so clients can follow.
- Treat any token you have pasted into an online tool as potentially exposed - which is exactly why this one never sends it anywhere.
Runs offline in your browser
The decoder is client-side JavaScript. Once the page has loaded, you can decode tokens with no network connection at all, and production credentials never leave your machine.
Decode a JWT in code or on the command line
| Where | How |
|---|---|
| JavaScript (npm) | import { jwtDecode } from 'jwt-decode'; jwtDecode(token) - payload only, no verification |
| Python (PyJWT) | jwt.decode(token, options={'verify_signature': False}) to read it, or pass the key to verify |
| Bash | echo $TOKEN | cut -d. -f2 | tr '_-' '/+' | base64 -d 2>/dev/null - Base64URL drops padding, so a short payload may need == appended |
| Browser console | JSON.parse(atob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/'))) |
Every one of these reads the token without checking the signature, which is fine for debugging and wrong for authorisation - see the section above.
Related tools
Tokens sit in the middle of a stack of formats. Read the raw segments with the Base64 decoder, tidy the payload with the JSON formatter, turn exp and iat into dates with the timestamp converter, and unescape a token pulled from a URL with the URL decoder.