What is JWT?

3 min read Updated 2026-02-05

JSON Web Token. A compact, URL-safe token format used for authentication and information exchange. Must be properly validated and stored securely.

Common in: REST APIs Single Page Applications Microservices Mobile apps SSO systems

Understanding JWT

JWTs contain three parts: header (algorithm), payload (claims/data), and signature. They're commonly used for stateless authentication but come with many security pitfalls. Common vulnerabilities include algorithm confusion attacks (changing alg to "none"), weak secrets that can be brute-forced, improper validation, and insecure storage.

Examples

  • Using JWTs for API authentication
  • Storing user roles and permissions in token claims
  • Single sign-on (SSO) implementations
  • Stateless session management

How to Prevent

  • Always specify allowed algorithms explicitly in verification
  • Use strong, random secrets (256+ bits) - generate with crypto.randomBytes()
  • Set appropriate expiration times (exp claim) - typically 15min to 1 hour
  • Don't store sensitive data in the payload - it's base64 encoded, NOT encrypted
  • Store tokens in httpOnly cookies, not localStorage (prevents XSS theft)
  • Implement token refresh mechanisms for long sessions
  • Use asymmetric algorithms (RS256) when tokens are verified by multiple services
  • Validate all claims: iss, aud, exp, nbf, iat

Code Examples

Algorithm Confusion Attack

The algorithm confusion attack tricks the server into using a different verification method than intended, allowing token forgery.

Vulnerable
// VULNERABLE: Accepting any algorithm from the token
const jwt = require('jsonwebtoken');

const decoded = jwt.verify(token, publicKey);
// If attacker changes alg: "RS256" to alg: "HS256"
// The library might use the public key as an HMAC secret
// Attacker can forge tokens using the public key!
Secure
// SECURE: Explicitly specify allowed algorithms
const jwt = require('jsonwebtoken');

const decoded = jwt.verify(token, publicKey, {
  algorithms: ['RS256']  // Only accept RS256
});

// Now alg: "HS256" or alg: "none" will be rejected

Weak Secret

Vulnerable
// VULNERABLE: Weak, guessable secret
const token = jwt.sign(payload, 'secret123');

// Attacker can brute-force common secrets using tools like jwt_tool
// "secret", "password", "123456" are cracked instantly
Secure
// SECURE: Strong, random secret (256+ bits)
const crypto = require('crypto');
const secret = crypto.randomBytes(64).toString('hex');
// Store this in environment variables, not code!

const token = jwt.sign(payload, process.env.JWT_SECRET);

// Or use asymmetric keys (RS256) for added security

Secure Token Storage

Vulnerable
// VULNERABLE: Storing JWT in localStorage
localStorage.setItem('token', jwt);

// XSS can steal this: localStorage.getItem('token')
// Any script on the page can access it
Secure
// SECURE: HttpOnly cookie (server-side)
res.cookie('token', jwt, {
  httpOnly: true,   // JavaScript cannot access
  secure: true,     // HTTPS only
  sameSite: 'strict', // CSRF protection
  maxAge: 3600000   // 1 hour expiry
});

// For SPAs: Consider token in memory + refresh token in httpOnly cookie

Real-World Incidents

Auth0 Critical Vulnerability

2015

Algorithm confusion vulnerability in Auth0's JWT library allowed attackers to forge tokens by switching from RS256 to HS256.

Impact: All applications using the vulnerable library were at risk of complete auth bypass

Plex Data Breach

2022

Attackers accessed a database containing user data. Passwords were hashed, but JWT secrets were also exposed, potentially allowing session hijacking.

Impact: 20+ million users notified to change passwords

Worried about JWT in your app?

Our security audits identify vulnerabilities like this before attackers do. Get expert manual review of your codebase.