How to Decode a JWT Safely

To decode a JWT safely, paste it into a decoder that runs entirely in your browser, such as the Toolstik JWT Decoder, and click Decode JWT to see the header and payload as JSON. Treat what you see as unverified: decoding shows what a token claims, not whether those claims are true. Prefer test or expired tokens over live production ones, and verify signatures only on your server.
Try it now
JWT Decoder
Loading tool…
Before you paste: a 20-second safety check
A JWT is usually a bearer credential. Anyone who has a valid, unexpired token can call your API as that user. So before pasting one anywhere:
- Prefer a test token from a dev or staging environment, or one that has already expired.
- Check where decoding happens. The Toolstik decoder is a client-side function: it splits the token, Base64URL-decodes the first two parts, and parses them as JSON in your browser tab. The token isn't sent to a server, and the analytics events it records don't include the token itself.
- Never paste signing secrets or private keys into any website. You don't need them to decode, and Toolstik never asks for them.
- Redact before sharing. In bug reports, include the decoded claims you need and leave out the signature. With the signature removed, a token can't be replayed.
Step by step: decode a JWT in Toolstik
- Open the JWT Decoder. The JWT token box has a sample token preloaded so you can see the output format.
- Replace it with your token. Paste only the token: strip any
Bearerprefix from anAuthorizationheader. - Click Decode JWT.
- Read the output. A note at the top reminds you that the tool "decodes JWTs locally" and "does not verify signatures or trust claims". Below it is one JSON block with a
headerobject and apayloadobject, already indented. - Click Copy to copy that JSON, or Reset to restore the sample.
The signature segment isn't displayed, because it's binary data that can't be read without a key.
For a token like this (signed with a throwaway demo secret):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImlhdCI6MTcwMDAwMDAwMCwiZXhwIjoxNzAwMDAzNjAwfQ.tulDXbfVqDWHrXTAOEEdlUfcIeFRjIRiBiMlcRqwA6Y
you get:
{
"header": {
"alg": "HS256",
"typ": "JWT"
},
"payload": {
"sub": "user_123",
"iat": 1700000000,
"exp": 1700003600
}
}
Reading the claims that matter for debugging
exp(expiry) andiat(issued at) are Unix timestamps in seconds.1700003600is 2023-11-14T23:13:20Z, one hour afteriat. Paste either value into the Unix Timestamp Converter to see it in UTC and your local time. Our guide on how to convert a Unix timestamp explains seconds versus milliseconds.nbf(not before) is also seconds. A token used beforenbfshould be rejected.audandisstell you which API the token is for and who issued it. A mismatch is a common cause of "valid token, still 401" errors.algin the header tells your server which algorithm to use. Your server should enforce an allow-list rather than trust this value.
A quick expiry check in JavaScript:
const payload = JSON.parse(atob(token.split(".")[1].replace(/-/g, "+").replace(/_/g, "/")));
const expired = payload.exp < Math.floor(Date.now() / 1000);
Note the / 1000. Date.now() returns milliseconds, while exp is in seconds. Mixing them up is one of the most common JWT bugs. This snippet is for debugging only, because it doesn't check the signature. (Plain atob also doesn't decode UTF-8, which is fine for numeric claims like exp.)
Troubleshooting decode errors
| Message | Likely cause | Fix |
|---|---|---|
| A JWT must have three parts separated by dots. | Truncated copy, extra text, or a five-part encrypted JWE | Re-copy the full token. JWEs can't be decoded without the key. |
| A JWT must have header, payload, and signature. | An empty segment, for example an unsigned token ending in a dot | Toolstik expects all three parts to be present. |
| Invalid JWT header: not valid JSON. | Often a leftover Bearer prefix | Remove everything before eyJ. |
| Invalid JWT payload: not valid Base64URL. | A character was lost or changed while copying | Copy the token again from the source. |
Accented or non-Latin characters look garbled (for example José instead of José)? The decoder reads the bytes without UTF-8 decoding. Copy just the payload segment, the text between the two dots, into the Base64 Encoder / Decoder, switch on URL-safe Base64, and click Decode. That tool decodes UTF-8 correctly. Then tidy the result with the JSON Formatter.
Decoding is not verifying
This is the rule that matters most. The header and payload are only encoded, not encrypted, and not protected by decoding. Anyone can change "role": "user" to "role": "admin", re-encode it, and paste it into a decoder, which will happily display it.
What stops that attack is signature verification on your server, using a maintained library (for example jose in Node.js or PyJWT in Python) with:
- the correct secret (HS256) or public key (RS256, ES256),
- an explicit list of allowed algorithms,
- checks on
exp,nbf,iss, andaud.
Never make an authorization decision, client-side or server-side, from a decoded payload you haven't verified. Decoded claims in the browser are fine for display, such as showing a user's name, but not for access control.
To learn what each segment contains and how the signature is computed, read JWT header vs payload vs signature explained. For the rest of the toolkit, see free developer tools online.
Frequently asked questions
Tools in this guide
JWT Decoder
Decode JWT header and payload locally. Inspect claims—signature is not verified.
Unix Timestamp Converter
Convert Unix timestamps to readable dates and dates back to epoch seconds or milliseconds.
Base64 Encoder / Decoder
Encode or decode text to Base64 with optional URL-safe output—all in your browser.
JSON Formatter & Validator
Format, validate, and minify JSON. Tree view with syntax error highlighting.
Keep reading
- DeveloperJWT Header vs Payload vs Signature ExplainedJWT header vs payload vs signature explained: what each segment contains, how Base64URL encoding and signing work, and why only the signature makes a token trustworthy.
- DeveloperHow to Convert a Unix Timestamp to a Date (and Back)How to convert a Unix timestamp to a readable date and back: seconds vs milliseconds, time zones, the 2038 problem, and copy-ready code for JS, Python, SQL, and bash.
- DeveloperFree Developer Tools Online: JSON, JWT, Base64, URL, Timestamp & RegexFree developer tools online that run in your browser: format JSON, decode JWTs, encode Base64 and URLs, convert Unix timestamps, and test JavaScript regex.