JWT Tokens: Security Best Practices and Common Vulnerabilities
Comprehensive guide to JWT token security. Learn about common vulnerabilities, best practices, and how to implement secure JWT authentication.
Understanding JWT Structure
JSON Web Tokens (JWT) consist of three parts separated by dots: Header.Payload.Signature. Understanding this structure is crucial for implementing secure JWT systems and identifying potential vulnerabilities.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Header: {"alg":"HS256","typ":"JWT"}
Payload: {"sub":"1234567890","name":"John Doe","iat":1516239022}
Signature: HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)Critical Security Vulnerabilities
1. Algorithm Confusion Attack (CVE-2016-10555)
Vulnerable Code:
// BAD: Accepts any algorithm
jwt.verify(token, secret);
// GOOD: Explicitly specify algorithm
jwt.verify(token, secret, { algorithms: ['HS256'] });2. Asymmetric to Symmetric Algorithm Confusion
Secure Implementation:
// Always verify with the expected algorithm
const verifyToken = (token, publicKey) => {
return jwt.verify(token, publicKey, {
algorithms: ['RS256'],
issuer: 'your-app',
audience: 'your-api'
});
};3. Weak Secret Keys
JWT Security Best Practices
1. Use Strong Secrets and Key Management
- Generate Cryptographically Strong Secrets
Use at least 256 bits of entropy for HMAC secrets. Use crypto.randomBytes() or equivalent.
- Rotate Keys Regularly
Implement key rotation strategies and support multiple active keys during transitions.
- Store Keys Securely
Use environment variables, key management services, or hardware security modules (HSMs).
// Generate a strong secret
const crypto = require('crypto');
const secret = crypto.randomBytes(64).toString('hex');
// Use environment variables
const JWT_SECRET = process.env.JWT_SECRET;
if (!JWT_SECRET || JWT_SECRET.length < 32) {
throw new Error('JWT_SECRET must be at least 32 characters');
}2. Implement Proper Token Validation
| Claim | Purpose | Validation |
|---|---|---|
| iss (Issuer) | Token issuer identity | Verify against expected issuer |
| aud (Audience) | Intended token recipient | Verify against your service identifier |
| exp (Expiration) | Token expiration time | Verify token hasn't expired |
| iat (Issued At) | Token issuance time | Verify token isn't from the future |
| nbf (Not Before) | Token activation time | Verify current time is after nbf |
3. Set Appropriate Expiration Times
Token lifetime should balance security and user experience:
- Access Tokens: 15-30 minutes
Short-lived tokens reduce impact if compromised.
- Refresh Tokens: 7-30 days
Longer-lived but stored securely and revocable.
- Admin Tokens: 5-15 minutes
Privileged operations should have shorter expiration.
const createToken = (payload, type = 'access') => {
const expiresIn = type === 'access' ? '15m' :
type === 'refresh' ? '7d' : '5m';
return jwt.sign(payload, secret, {
expiresIn,
issuer: 'your-app',
audience: 'your-api',
algorithm: 'HS256'
});
};Advanced Security Measures
1. Token Blacklisting/Revocation
Implement token revocation for compromised or logged-out users:
// Redis-based token blacklist
const blacklistToken = async (tokenId, expiresAt) => {
const ttl = Math.floor((expiresAt - Date.now()) / 1000);
await redis.setex(`blacklist:${tokenId}`, ttl, '1');
};
const isTokenBlacklisted = async (tokenId) => {
return await redis.exists(`blacklist:${tokenId}`);
};2. Rate Limiting and Monitoring
- Failed Authentication Attempts
Monitor and rate-limit failed JWT validation attempts.
- Token Usage Patterns
Detect unusual token usage patterns that might indicate compromise.
- Algorithm Manipulation
Log and alert on tokens with unexpected algorithms.
3. Secure Token Storage
| Storage Method | Security Level | XSS Protection | CSRF Protection |
|---|---|---|---|
| localStorage | ❌ Low | ❌ Vulnerable | ✅ Protected |
| httpOnly Cookie | ✅ High | ✅ Protected | ⚠️ Needs CSRF protection |
| Secure Memory | ✅ Highest | ✅ Protected | ✅ Protected |
JWT Security Checklist
- ✅ Algorithm Whitelist
Explicitly specify allowed algorithms in verification.
- ✅ Strong Secrets
Use cryptographically strong secrets (256+ bits).
- ✅ Claim Validation
Validate iss, aud, exp, iat, and nbf claims.
- ✅ Short Expiration
Use appropriate token lifetimes (15-30 min for access tokens).
- ✅ Secure Storage
Store tokens securely (httpOnly cookies or secure memory).
- ✅ Token Revocation
Implement token blacklisting for logout/compromise scenarios.
- ✅ Rate Limiting
Monitor and rate-limit authentication attempts.
- ✅ HTTPS Only
Always transmit JWTs over HTTPS in production.
Testing JWT Security
Regular security testing helps identify vulnerabilities:
- Algorithm Confusion Tests
Test with 'none' algorithm and RS256 to HS256 conversions.
- Signature Verification
Attempt to use tokens with modified signatures.
- Expired Token Handling
Verify expired tokens are properly rejected.
- Claim Manipulation
Test with modified claims (role escalation attempts).
Analyze JWTs with Our Security Tool
Use our advanced JWT analyzer to decode tokens, verify signatures, perform security analysis, and test for common vulnerabilities. Our tool supports multiple algorithms including HMAC, RSA, and ECDSA, with comprehensive security checking features.