JWT Decoder & Security Analyzer (Free, In-Browser)
JWT Decoder & Security Analyzer
{}{}Decode any JSON Web Token and inspect the header, payload, and common security mistakes. The analyzer runs locally in your browser. The token is not sent to CodeCrackers or anyone else.
Use it when you are debugging an API login, reviewing a mobile app session, or checking whether a token you captured in Burp is expired, unsigned, or stuffed with data that should never sit in a JWT.
How to use this JWT decoder
- Copy the token from DevTools, Postman, Burp, or an
Authorization: Bearerheader. - Paste it in the box above. Decoding starts as soon as the string looks like a JWT.
- Read the header (algorithm, type, kid) and the payload (claims).
- Work through the findings. Red means fix it before production. Yellow means validate it on the server even if the app “works.”
You do not need an account. You do not need to paste a signing key. Signature verification stays on your machine, in your app, or in a local script.
What a JWT actually is
A compact JWT is three Base64URL pieces separated by dots:
header.payload.signature
The header and payload are JSON. Base64URL is encoding, not encryption. Anyone who has the token can read those two parts. The signature is the only piece that proves a trusted party minted the token — and only if the server checks it with the right key and rejects garbage algorithms.
That last sentence is where real applications fail. Libraries that accept alg: none, confuse a public RSA key with an HMAC secret, or skip iss / aud / exp checks are why JWT bugs still show up in pentests.
Header fields you should actually look at
alg— HS256, RS256, ES256, or the dangerous valuenone.typ— usuallyJWT.kid— key id. Useful for key rotation. Dangerous if the app fetches a key from a URL built out of this string.jku/x5u— remote key URLs. Treat as untrusted. These belong in a pentest report if the server honors them blindly.
Payload claims that matter in production
| Claim | Meaning | What to validate |
|---|---|---|
iss | Who minted the token | Exact issuer URL, not “starts with” |
aud | Who the token is for | Your API’s audience value |
sub | Which user or client | Stable id, not an email you never check |
exp | Expiry (Unix seconds) | Reject if now >= exp |
nbf | Not before | Reject if now < nbf |
iat | Issued at | Helps detect absurd lifetimes |
jti | Token id | Use if you need revoke / replay control |
Unix timestamps in JWTs are seconds, not milliseconds. If exp decodes to the year 1970 or the year 56000, someone mixed units up.
Findings this analyzer looks for
1. alg: none or a missing algorithm
Some older libraries treated none as “valid, just unsigned.” An attacker edits the payload, sets alg to none, strips the signature, and the server accepts it. If you see none on a token your API accepts, that is a critical finding. Disable the algorithm in the library config. Do not try to “filter it in application code” and hope every future endpoint remembers.
2. HS256 on a public API
HMAC (HS256 / HS384 / HS256) uses one shared secret. That is fine inside one service you control. It is a poor default when a SPA, a mobile app, and three microservices all need to check the same token. RSA or EC signatures let you distribute a public key and keep the private key on the auth server.
HS256 also enables the classic key-confusion bug: attacker signs a token with HS256 using the server’s RSA public key as the HMAC secret, because the public key is public. Servers must pin the expected algorithm, not trust the header.
3. Expired tokens that still work
If this page says expired and the API still returns 200, session handling is broken. Check clock skew (a minute or two is normal; a day is not), check whether the gateway validates JWT while a legacy endpoint does not, and check whether refresh tokens are being sent as access tokens.
4. Missing iss or aud
A token minted for api-test.example.com should not work on api.example.com. If you only check the signature, you have built a skeleton key for every environment that shares the key.
5. Secrets sitting in the payload
Email is common. Passwords, API keys, raw session ids, and card data are not. Remember: the payload is readable. If you need confidentiality, encrypt at a higher layer (JWE) or do not put the data in the token.
6. kid used as a file path or URL
We flag kid so you remember to test it. Try values like ../../tmp/evil, a URL to your own JWKS, or a key from another tenant. The safe pattern is: kid is an allow-listed identifier into a local JWKS. Nothing is fetched from the token itself.
JWT vs “the user is logged in”
Decoding is not authentication. This page will happily decode a token that was signed with password or not signed at all. Your API must:
- Verify the signature with a pinned algorithm and the right key.
- Reject
none. - Check
exp,nbf,iss,aud. - Only then read
suband scopes.
If you skip step 1, everything after it is theater.
How pentesters usually grab the token
- Browser DevTools → Application → Local Storage / Session Storage / Cookies
- DevTools → Network → request header
Authorization - Burp / OWASP ZAP HTTP history
- Mobile: Frida, objection, or a proxy with TLS unpinning on a device you own
- Server logs (tokens should not be logged; if they are, that is another finding)
Paste only tokens from systems you are allowed to test. A JWT can contain personal data.
Safe workflow for developers
- Decode here to see claims while you build.
- Confirm expiry math against
/unix-timestamp-converter/. - Pretty-print nested JSON in the payload with
/json-formatter-beautifier/. - Verify signatures in unit tests or with a local script. Do not put production secrets in a website form.
- When you ship, add security headers so stolen tokens are harder to use from a hostile page — start with
/cyber-security/if you want that done on a live WordPress or API site.
Common JWT mistakes we see on real apps
- Access tokens that live 7 days because “refresh was hard.”
- The same HS256 secret in Git, CI, staging, and production.
audset but never checked.- Custom claim
admin: truein a token the client can get re-issued for. - Putting PII in the payload and calling it “encrypted because it is a JWT.”
- Accepting tokens from any
issthat shares a parent domain.
None of these require a fancy exploit. They require reading the token, which is what this page is for.
What this tool will not do
It will not crack HS256 secrets. An online cracker invites abuse and is the wrong place for that work. If you are testing your token on your engagement, use Hashcat or jwt-cracker locally with a wordlist you are authorized to use.
It will not talk to your auth server. There is no “verify against production” button on purpose.
FAQ
Is it safe to paste a JWT here?
Decoding runs in your browser with JavaScript. The token is not posted to our server. Still: treat any live production token as sensitive. Prefer staging tokens when you can.
Does decoding verify the signature?
No. Decoding only Base64URL-decodes the header and payload. Verification needs the secret or public key and must happen in your application.
Why is my token marked expired when the app still works?
Either the app is not checking exp, the clock on the device is wrong, or you pasted a refresh token / different token than the one the app is sending.
What does alg: none mean?
It means “this token has no signature algorithm.” Some libraries historically accepted that as valid. It should always be rejected.
HS256 or RS256?
HS256 is simpler for a single backend. RS256 / ES256 is the better default when more than one service must validate tokens. Pin the algorithm on the server either way.
Can I decode a JWE (encrypted token)?
Not with this decoder. JWE has five parts and is encrypted. If you see five dot-separated segments, you need the recipient key, not a JWT decoder.
Why do dates look wrong?
JWT times are Unix seconds. If a library wrote milliseconds into exp, the date will look like it is in the year 50,000. Fix the issuer.
Do you store tokens for training or ads?
No. This widget does not submit the textarea to the server. Ads, if present elsewhere on the page, do not receive the token from this script.