How JWT Works
A JWT consists of three parts separated by dots (.):
- Header - Contains the token type (JWT) and signing algorithm (e.g., HS256, RS256)
- Payload - Contains the claims (data) like user ID, roles, and expiration time
- Signature - Verifies the token hasn't been tampered with
Example JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4iLCJpYXQiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Each part is Base64URL encoded, making JWTs safe for use in URLs and HTTP headers.
Why Use JWT?
JWT tokens are popular for several reasons:
1. Stateless Authentication
The server doesn't need to store session data. All user info is in the token itself.
2. Compact & Portable
JWTs are small and can be sent in HTTP headers, URL parameters, or cookies.
3. Self-Contained
The token contains all the information needed to authenticate the user, reducing database queries.
4. Cross-Domain / Microservices
JWTs work seamlessly across different domains and services.
5. Mobile-Friendly
Unlike cookies, JWTs work well with mobile apps and native clients.
JWT Claims Explained
Claims are statements about an entity (usually the user). There are three types:
Registered Claims (Standard)
iss(Issuer) - Who created the tokensub(Subject) - Who the token is about (usually user ID)aud(Audience) - Who the token is forexp(Expiration) - When the token expires (Unix timestamp)nbf(Not Before) - Token not valid before this timeiat(Issued At) - When the token was createdjti(JWT ID) - Unique identifier for the token
Public Claims - Custom claims registered in the IANA JWT Registry
Private Claims - Custom claims agreed upon by parties (e.g., role, permissions)
JWT in JavaScript
Here's how to work with JWTs in JavaScript:
// Decode JWT (without verification)
function decodeJwt(token) {
const [header, payload] = token.split('.').slice(0, 2);
return {
header: JSON.parse(atob(header)),
payload: JSON.parse(atob(payload))
};
}
// Using jwt-decode library (recommended)
import jwt_decode from 'jwt-decode';
const decoded = jwt_decode(token);
// Using jsonwebtoken (Node.js - with verification)
const jwt = require('jsonwebtoken');
// Sign a token
const token = jwt.sign(
{ userId: 123, role: 'admin' },
'your-secret-key',
{ expiresIn: '1h' }
);
// Verify a token
try {
const decoded = jwt.verify(token, 'your-secret-key');
console.log(decoded);
} catch (err) {
console.log('Invalid token');
}JWT in Python
Python's PyJWT library makes JWT handling simple:
import jwt
from datetime import datetime, timedelta
# Your secret key (keep this safe!)
SECRET_KEY = 'your-secret-key'
# Create a token
payload = {
'user_id': 123,
'username': 'john_doe',
'role': 'admin',
'exp': datetime.utcnow() + timedelta(hours=1), # Expires in 1 hour
'iat': datetime.utcnow()
}
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
print(token)
# Decode and verify a token
try:
decoded = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
print(decoded)
except jwt.ExpiredSignatureError:
print('Token has expired')
except jwt.InvalidTokenError:
print('Invalid token')
# Decode without verification (for debugging only)
decoded = jwt.decode(token, options={"verify_signature": False})JWT Signing Algorithms
JWTs can be signed using different algorithms:
Symmetric (Shared Secret)
- HS256 (HMAC + SHA-256) - Most common, uses one secret key
- HS384 / HS512 - Stronger variants
Asymmetric (Public/Private Key)
- RS256 (RSA + SHA-256) - Uses private key to sign, public key to verify
- RS384 / RS512 - Stronger variants
- ES256 (ECDSA) - More efficient than RSA
When to use which:
- HS256: Single server or trusted environment
- RS256: Distributed systems, public verification, OAuth providers
JWT Security Best Practices
DO:
ā Use strong, random secret keys (256+ bits)
ā Set short expiration times (15min - 1hr for access tokens)
ā Use refresh tokens for long sessions
ā Validate all claims (exp, iss, aud)
ā Use HTTPS always
ā Store tokens securely (httpOnly cookies preferred)
DON'T:
ā Put sensitive data in payload (it's only encoded, not encrypted)
ā Use weak or hardcoded secrets
ā Ignore the "alg" header (prevents "none" algorithm attacks)
ā Store tokens in localStorage (XSS vulnerable)
ā Send tokens in URLs (can be logged)
Access vs Refresh Tokens
A common pattern uses two types of tokens:
Access Token
- Short-lived (15 minutes - 1 hour)
- Used to access protected resources
- Sent with every API request
- Contains user info and permissions
Refresh Token
- Long-lived (days to weeks)
- Used only to get new access tokens
- Stored securely (httpOnly cookie)
- Can be revoked from server
1Client Server2 | |3 |------- Access Token -------->| API request4 |<------ Response -------------|5 | |6 | (Access token expires) |7 | |8 |------- Refresh Token ------->| Get new tokens9 |<------ New Access Token -----|
Common JWT Attacks & Prevention
1. Algorithm Confusion (None Algorithm)
Attack: Changing "alg" to "none" to bypass verification
Prevention: Always validate the algorithm server-side
2. Secret Brute Force
Attack: Guessing weak secrets
Prevention: Use strong, random 256+ bit keys
3. Token Theft (XSS/CSRF)
Attack: Stealing tokens via JavaScript or cross-site requests
Prevention: httpOnly cookies, CSRF tokens, short expiry
4. Payload Tampering
Attack: Modifying claims without re-signing
Prevention: Always verify signatures server-side
5. Token Replay
Attack: Reusing stolen tokens
Prevention: Short expiry, token blacklisting, jti claim
Frequently Asked Questions
What is JWT used for?
JWT is primarily used for authentication and authorization in web applications and APIs. After login, the server issues a JWT that the client sends with subsequent requests to prove identity and access permissions.
Is JWT secure?
Yes, JWT is secure when implemented correctly. Use strong secrets, short expiration times, HTTPS, and always verify signatures. However, the payload is only encoded (not encrypted), so don't store sensitive data in it.
What's the difference between JWT and cookies?
Cookies are storage mechanisms sent automatically with requests. JWT is a token format that can be stored in cookies, localStorage, or memory. JWTs are stateless and work across domains, while session cookies require server-side storage.
Why does my JWT keep expiring?
JWTs have an expiration time (exp claim) for security. Use refresh tokens to get new access tokens without requiring the user to log in again. Short expiration (15min-1hr) is a security best practice.
Can I decode a JWT without the secret key?
Yes, you can decode the header and payload without the secret (they're just Base64URL encoded). However, you CANNOT verify the signature without the secret, meaning you can't trust the contents unless verified.
Should I use HS256 or RS256?
Use HS256 (symmetric) for simple apps where the same server signs and verifies. Use RS256 (asymmetric) for distributed systems, microservices, or when you need public verification (like with OAuth providers).