JWT Decoder: The Ultimate Guide to JSON Web Tokens (2026)
Table of Contents
JSON Web Tokens (JWT) have become the de facto standard for securing modern web applications, microservices, and mobile APIs. Unlike traditional session-based authentication (where the server stores user data in memory), JWTs are stateless—the token itself contains all the information needed to identify the user.
But with great power comes great responsibility. A poorly implemented JWT system can open your application to account takeovers. This guide, written by a security engineer with 15+ years of experience, breaks down the anatomy of a token, how to debug them safely, and how to verify them securely.
The 3 Parts of a JWT
A JWT is just a long string of characters consisting of three parts, separated by dots (.).
It looks like this: Header.Payload.Signature.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
1. Header (Red)
Contains metadata about the token, typically the type (JWT) and the signing algorithm (HMAC SHA256 or RSA).
2. Payload (Purple)
Contains the "claims" (data). This is where you put user ID, roles, and expiration time.
- Registered Claims: Standard fields like
exp(expiration),iss(issuer),sub(subject). - Public/Private Claims: Custom fields like
"role": "admin"or"email": "user@example.com".
3. Signature (Blue)
The security seal. It's calculated by taking the encoded header, the encoded payload, a secret key, and the algorithm specified in the header.
How Decoding Actually Works
Many developers confuse "decoding" with "decrypting." Decoding a JWT is trivial. The Header and Payload are just Base64Url encoded JSON. Anyone who has the token can see the data inside.
// Take the middle part (Payload)
const payloadBase64 = token.split('.')[1];
// Decode standard Base64
const decodedJson = atob(payloadBase64);
// Result: {"sub":"1234567890","name":"John Doe","iat":1516239022}
// No secret key needed!
Critical Security Warning
NEVER store sensitive information like passwords, credit card numbers, or social security numbers in the JWT payload. Since the payload is easily readable by the client (and anyone snooping on the network if not using HTTPS), that data is effectively public.
Security: Signing vs. Encryption
Signing (JWS): Ensures integrity. "I promise this data hasn't been changed." The data is visible, but if a hacker changes "role": "user" to "role": "admin", the signature validation will fail.
Encryption (JWE): Ensures confidentiality. The data is scrambled and unreadable without a private key. Most standard JWTs (like OIDC ID Tokens) are Signed, NOT Encrypted.
Decode & Debug JWTs
Paste a token to view its header and payload instantly. Check expiration times and structure errors without sending data to a server.
Open JWT DecoderValidating Signatures (The Right Way)
When your server receives a JWT, decoding is not enough. You must verify the signature to ensure the token was issued by you.
const jwt = require('jsonwebtoken');
// Verify using the Secret Key stored on server
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
console.log("Valid token!", decoded);
} catch(err) {
// Signature mismatch OR Token expired
console.error("Invalid token!");
}
Common Security Pitfalls
1. The "None" Algorithm Attack
Some libraries historically allowed tokens to set "alg": "none" in the header. A hacker
could create a token with admin rights, remove the signature, set alg to none, and the server would
accept it. Fix: Always explicitly define allowed algorithms (e.g.,
['HS256']) in your verification function.
2. Weak Secrets
If you use a simple secret like "secret123", hackers can brute-force your key offline in seconds using tools like Hashcat. Fix: Use long, random, high-entropy secrets (64+ chars).
Frequently Asked Questions
What is the difference between HS256 and RS256?
How do I invalidate a JWT (Logout)?
Where should I store JWTs on the client?
localStorage, any malicious JS injection can steal
your users' tokens. Cookies with the Secure and HttpOnly flags are
inaccessible to JavaScript.
Can I change the payload after the token is created?
What happens if the token expires?
exp (expiration) claim is a timestamp. Standard libraries automatically check
this during verification. If Date.now() > exp, the library throws a
"TokenExpiredError". You should catch this error on the frontend and redirect the user to login
or use a refresh token to get a new access token.