JSON Web Tokens (JWTs) are one of the most common ways to handle authentication and authorization in modern applications.
They power login systems, access tokens, API authentication, single sign-on flows, and more.
But despite their popularity, JWTs are also frequently misunderstood, which leads to subtle — and sometimes severe — security issues.
This guide explains exactly how JWTs work, how to use them safely, and what to watch out for. No diagrams, no complexity — just clear explanations.
What Is a JWT?
A JWT (JSON Web Token) is a compact, URL-safe token used to securely transmit information between two parties.
It looks like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
A JWT consists of three Base64-encoded parts:
- Header - algorithm + token type
- Payload - user or session data
- Signature - proves the token hasn’t been tampered with
When decoded, it becomes human-readable JSON.
You can quickly view the contents using our JWT Decoder at credential.help, which runs fully in your browser.
What JWTs Are Actually Used For
JWTs are most commonly used as:
- access tokens for APIs
- ID tokens in OAuth / OpenID Connect
- session tokens in stateless backends
- temporary proof of identity between services
Their biggest advantage is that JWTs are self-contained — the server doesn’t need to look anything up in a database to validate them.
How JWT Verification Works (Simple Version)
When a server receives a JWT, it:
- Decodes the header and payload
- Recreates the signature using the server’s secret or private key
- Compares the recreated signature with the one in the token
- If they match → the token is valid
- If they don’t → the token has been tampered with or forged
This makes JWTs fast and scalable.
But it also means any mistake in how you generate or validate tokens can break security completely.
What’s Inside a Typical JWT?
Header (Base64-encoded JSON)
{
"alg": "HS256",
"typ": "JWT"
}
Payload (Base64-encoded JSON)
Common claims include:
sub- user IDiat- issued atexp- expirationemail- user emailroles- permissions
Signature
A cryptographic hash using either:
- a secret key (HS256)
- a public/private key pair (RS256, ES256)
Are JWTs Encrypted?
No.
This is one of the biggest misconceptions.
JWTs are signed, not encrypted.
Anyone who has the token can read the payload — even if they cannot modify it.
This is why you should never store sensitive data inside a JWT, such as:
- passwords
- API keys
- personal information
- internal secrets
JWTs provide authenticity, not confidentiality.
Common JWT Vulnerabilities Developers Should Avoid
1. Using alg: none
This infamous vulnerability allowed attackers to bypass signatures entirely.
Modern libraries block it, but make sure you don’t accept unsigned tokens.
2. Storing JWTs in localStorage
If an attacker injects JavaScript (XSS), they can steal tokens easily.
Prefer:
- HttpOnly cookies
- Secure cookies
- SameSite cookies
These cannot be read by JavaScript.
3. Not verifying token expiration
An expired token should be treated as invalid.
Always check exp before accepting a JWT.
4. Using the wrong signing algorithm
Use:
- HS256 for simple server-only apps
- RS256 or ES256 for distributed systems (private key signs, public key verifies)
Mixing algorithms or switching without caution is dangerous.
5. Making tokens last too long
Long-lived tokens increase the blast radius if they leak.
Keep access tokens short-lived and issue refresh tokens when needed.
6. Storing sensitive user data inside the payload
Remember: JWTs are readable by anyone.
Only store what is strictly necessary for authentication or authorization.
Best Practices for JWT Security
Here’s what a safe JWT setup looks like:
- Use short expiration times (
exp,iat,nbf) - Do not store JWTs in localStorage
- Validate algorithm and signature on every request
- Rotate signing keys periodically
- Use refresh tokens if users need longer sessions
- Keep your payload small and non-sensitive
Following these basics will protect you from the majority of JWT-related attacks.
How to Decode JWTs Safely
Decoding a JWT should never send the token to a server — it’s sensitive, after all.
Our free JWT Decoder at credential.help runs entirely in your browser using window.crypto, ensuring:
- no network requests
- no storage
- no tracking
It’s the safest way to inspect the contents of a token without exposing it.
Example of a Decoded JWT (Do Not Reuse)
Header
{
"alg": "HS256",
"typ": "JWT"
}
Payload
{
"sub": "user_123",
"email": "[email protected]",
"iat": 1739491200,
"exp": 1739494800
}
This example shows common fields — but keep actual tokens private.
Final Thoughts
JWTs are powerful tools for modern authentication, but they come with responsibilities.
Used correctly, they offer a fast, scalable, stateless way to manage identity.
Used incorrectly, they expose systems to serious vulnerabilities.
Keep tokens short-lived, signed using strong algorithms, stored securely, and validated on every request — and you’ll be on the right path.
If you ever need to inspect a JWT, you can use the JWT Decoder at credential.help to safely decode tokens directly in your browser.