JWTs are the most common authentication token format in web applications. Every time you log in, an API issues a JSON Web Token that carries your identity, permissions, and often personal details. When something goes wrong — an expired session, a rejected request, a teammate asking “what’s in this token?” — the first instinct is to decode it.
Most online JWT decoders work. The question is whether you should trust them with your token.
What’s actually in a JWT
A JWT is three base64url-encoded strings separated by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NSIsIm5hbWUiOiJBbGljZSIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Decode the first two parts and you get JSON:
// Header
{
"alg": "HS256",
"typ": "JWT"
}
// Payload
{
"sub": "12345",
"name": "Alice",
"iat": 1516239022
}
The signature is a cryptographic hash proving the token was issued by someone with the secret. Anyone can decode the payload — that’s not the security boundary. The boundary is whether you can verify the signature.
Decoding vs verifying
This distinction matters:
- Decoding = base64-decoding the JSON so you can read it. No secret required. Anyone can do it.
- Verifying = checking the signature against a known secret to confirm the token wasn’t tampered with. Requires the secret.
Most online decoders only decode. They show you the header and payload but never ask for your secret — because they’re not verifying, just displaying.
For debugging (what claims does this token have, when does it expire), decoding is enough. For authentication, you need verification — and it has to happen on infrastructure you control.
Standard JWT claims to check
When you decode a JWT, look for these registered claims:
| Claim | Meaning | What to check |
|---|---|---|
exp |
Expiration time (Unix timestamp) | Is it in the future? |
nbf |
Not before (Unix timestamp) | Is it in the past? |
iat |
Issued at (Unix timestamp) | How old is the token? |
iss |
Issuer | Does it match your auth server? |
aud |
Audience | Does it match your API? |
sub |
Subject (user ID) | Is it the expected user? |
The most common reason a “valid” token fails: it’s expired. Check exp first.
How to decode a JWT in your browser
You don’t need a third-party tool for this. A JWT is just three base64url strings. But if you’d rather not memorize the decode command, a browser-based decoder does the same thing without uploading your token:
- Paste the JWT into the decoder
- See the decoded header, payload, and signature
- Check the
expclaim to see if the token is expired - Verify the algorithm in the header matches what you expect
The JWT decoder on DevSpeedTools runs entirely in your browser. No network request, no upload, no log. Open DevTools → Network, paste a token, and confirm that nothing leaves your machine.
When you need verification (not just decoding)
If you’re debugging an auth issue and need to know whether the token is valid — not just what it contains — you need to verify the signature. This has to happen with the same secret or public key your auth server uses.
Options that don’t involve pasting your secret into a website:
- Node.js:
jsonwebtoken.verify(token, process.env.JWT_SECRET) - Python:
jwt.decode(token, key, algorithms=['HS256']) - Go:
token, err := jwt.Parse(tokenString, keyFunc) - CLI:
jwt-cli(Rust) orpyjwtwith a one-liner
Never paste a production secret into an online tool. The token is not a secret. The contents often are.
The TL;DR
- Use a browser-based decoder for quick inspection. No upload, no leak.
- Use a CLI or your own code for verification. Never paste a secret into a website.
- Check
expfirst — expired tokens are the cause of most “my token stopped working” issues.