JWT Security Best Practices for 2024

Critical security considerations when implementing JWT authentication in your applications.

securitybest-practicesauthentication

JWT Security Best Practices

JWTs are powerful but come with security considerations. Follow these practices to keep your implementation secure.

1. Use Strong Secrets

// BAD: Weak secret
const secret = "password123";

// GOOD: Strong, random secret (256 bits minimum)
const secret = crypto.randomBytes(32).toString('hex');

2. Always Validate Tokens

// Verify signature, expiration, and issuer
const jwt = require('jsonwebtoken');

try {
const decoded = jwt.verify(token, secret, {
algorithms: ['HS256'], // Specify allowed algorithms
issuer: 'your-app',
audience: 'your-api',
});
} catch (err) {
// Token invalid - reject request
}

3. Set Short Expiration Times

// Access tokens: 15 minutes
const accessToken = jwt.sign(payload, secret, { expiresIn: '15m' });

// Use refresh tokens for longer sessions
const refreshToken = jwt.sign({ userId }, refreshSecret, { expiresIn: '7d' });

4. Never Store Sensitive Data in Payload

The payload is only Base64 encoded, not encrypted:

// BAD: Sensitive data exposed
{
"userId": 123,
"password": "secret", // NEVER do this
"creditCard": "4111..." // NEVER do this
}

// GOOD: Only store references
{
"userId": 123,
"role": "admin"
}

5. Protect Against Algorithm Confusion

// Always specify allowed algorithms
jwt.verify(token, secret, { algorithms: ['HS256'] });

// Reject tokens with "alg": "none"

6. Secure Token Storage (Frontend)

// For web apps: HttpOnly cookies (preferred)
// Protects against XSS attacks

// If using localStorage (less secure):
// - Never store refresh tokens
// - Implement CSRF protection

7. Implement Token Revocation

Since JWTs are stateless, implement a blacklist for revoked tokens:

const revokedTokens = new Set();

function isRevoked(token) {
const { jti } = jwt.decode(token);
return revokedTokens.has(jti);
}

Frequently Asked Questions

Common questions about this topic

Access tokens should be short-lived: 15-60 minutes is common. Shorter is more secure but requires more frequent refresh. Use refresh tokens (stored securely, server-validated) for longer sessions. Balance security with user experience.

HttpOnly cookies are more secure (immune to XSS). localStorage is vulnerable to XSS attacks but easier to use with APIs. Best practice: HttpOnly cookie for refresh token, short-lived access token in memory. Never store tokens in regular cookies or sessionStorage.

JWTs are stateless, so revocation requires extra mechanisms: 1) Token blacklist (check against database), 2) Short expiration + refresh tokens (revoke refresh token), 3) Token versioning (increment version on logout), 4) Change the signing secret (invalidates ALL tokens).