JWT Decoder
Decode and inspect JSON Web Tokens. Paste your JWT below to view the header and payload:
What is a JWT?
JSON Web Token (JWT) is a compact, URL-safe way to represent claims between two parties. JWTs are commonly used for authentication and authorization in web applications and APIs.
JWT Structure
A JWT consists of three parts separated by dots:
header.payload.signature| Part | Contents | Purpose |
|---|---|---|
| Header | Algorithm, token type | Describes how the token is signed |
| Payload | Claims (user data) | Contains the actual data/claims |
| Signature | Encrypted hash | Verifies the token is authentic |
Common JWT Claims
The payload typically contains these standard claims:
| Claim | Name | Description |
|---|---|---|
sub | Subject | Who the token is about (usually user ID) |
iat | Issued At | When the token was created (Unix timestamp) |
exp | Expiration | When the token expires (Unix timestamp) |
iss | Issuer | Who issued the token |
aud | Audience | Intended recipient of the token |
Security Considerations
Important: This tool decodes JWTs but does not verify signatures. Anyone can decode a JWT and read its contents — the signature only prevents tampering.
- Never trust a JWT without verifying its signature on your server
- Don't store sensitive data in JWT payloads (they're not encrypted)
- Always check the
expclaim to reject expired tokens - Validate the
issandaudclaims match expected values
JWT vs Session Cookies
| Feature | JWT | Session Cookie |
|---|---|---|
| Storage | Client-side | Server-side |
| Scalability | Stateless, easy to scale | Requires session store |
| Revocation | Harder (needs blocklist) | Easy (delete session) |
| Size | Larger (contains data) | Small (just an ID) |
Working with JWTs in Code
JavaScript
// Decode without verifying (like this tool)
function decodeJWT(token) {
const payload = token.split('.')[1];
return JSON.parse(atob(payload));
}
// With a library (recommended for verification)
import jwt from 'jsonwebtoken';
const decoded = jwt.verify(token, secretKey);Python
import jwt
# Decode without verifying
decoded = jwt.decode(token, options={"verify_signature": False})
# Decode with verification
decoded = jwt.decode(token, secret_key, algorithms=["HS256"])Related Tools
- Base64 Encode/Decode — Encode or decode Base64 data
- JSON Validator — Validate JSON syntax
- JSON Pretty Print — Format JSON for readability
Frequently Asked Questions
Is it safe to decode a JWT in the browser?
Yes, decoding is safe. JWTs are not encrypted — they're just Base64-encoded. The signature protects against tampering, not reading. Never put sensitive information in a JWT that you wouldn't want users to see.
Why does my JWT show as expired?
The exp claim is a Unix timestamp. If the current time is past this value, the token is expired. Tokens typically expire in minutes to hours for security.
Can I verify the signature with this tool?
No. Signature verification requires the secret key or public key used to sign the token, which should never be shared publicly. Use server-side code to verify signatures.
Common Mistakes & Pro Tips
- Decoding is not verifying — the signature is unchecked — This tool Base64URL-decodes the header and payload so you can read them, but it does not verify the signature against a secret or public key. A decoded token can still be expired, tampered with, or forged; never trust its contents for authorization without verifying the signature server-side.
- A JWT is signed, not encrypted — the payload is public — Anyone holding the token can decode the payload and read every claim; signing only proves integrity, not confidentiality. Never put passwords, secret keys, or sensitive personal data in a JWT payload, because it is effectively plaintext to whoever receives it.
- exp and iat are Unix seconds, not milliseconds — Per RFC 7519, exp, iat, and nbf are NumericDate values — seconds since 1970-01-01 UTC. JavaScript's Date.now() returns milliseconds, so multiply these claims by 1000 before constructing a Date, or you'll compute a timestamp in 1970.
- JWTs use Base64URL, not standard Base64 — The three segments are encoded with the URL-safe alphabet (- and _ instead of + and /) and typically have their = padding stripped. A standard Base64 decoder may fail on a JWT segment, which is why a dedicated decoder handles the padding and alphabet correctly.
- alg: none is a red flag — A header specifying "alg": "none" means the token is unsigned, a historically exploited way to bypass verification. If you see it on a token that's supposed to be authenticated, treat the token as untrusted and reject it on the server.
Frequently Asked Questions
Does decoding a JWT verify that it's valid?
No. Decoding only Base64URL-decodes the header and payload so you can read them; it performs no signature verification whatsoever. To confirm a token is authentic and untampered, the receiving server must verify the signature using the issuer's secret (for HMAC) or public key (for RSA/ECDSA), and also check claims like exp. Treat any decoded payload as unverified until that happens.
Can anyone read the contents of my JWT?
Yes. A standard JWT is signed but not encrypted, so its payload is just Base64URL-encoded text that anyone with the token can decode and read. The signature prevents undetected modification, not reading. For this reason you must never place secrets, passwords, or sensitive personal information in a JWT payload.
How do I check when a token expires?
Look at the exp claim in the decoded payload. It's a Unix timestamp in seconds (UTC), so convert it by multiplying by 1000 to get JavaScript milliseconds, or compare it directly to the current time in seconds. If exp is earlier than now, the token is expired — though only signature verification confirms the token was legitimate in the first place.
What do the iss, iat, and sub claims mean?
These are registered claims from RFC 7519: iss is the issuer (who created the token), iat is issued-at (a Unix-seconds timestamp), and sub is the subject (usually the user or entity the token is about). Other common ones include aud (intended audience), nbf (not valid before), and jti (a unique token ID). They're conventions, so an issuer may include only some of them.
Why are there three parts separated by dots?
A JWT is header.payload.signature, with each part Base64URL-encoded and joined by periods. The header names the signing algorithm and token type, the payload holds the claims, and the signature is computed over the first two parts to detect tampering. This decoder shows you the header and payload; the signature can only be checked with the right key.
Is it safe to paste a real token into this decoder?
Yes, from a transmission standpoint — decoding happens entirely in your browser and the token is never uploaded. That said, remember a live token grants whatever access it represents, so avoid pasting it anywhere you don't control, and prefer expired or test tokens when sharing screenshots.
Can I decode an expired or invalid JWT?
Yes. Decoding is purely structural, so expiry, a bad signature, or a wrong audience don't stop you from reading the header and payload. This is useful for debugging — you can inspect why a token was rejected — but it also underlines that decoding tells you nothing about whether the token is trustworthy.