What is a JSON Web Token?
A JSON Web Token (JWT) is a compact, self-contained way to represent claims between two parties. JWTs are widely used for authentication and authorization in modern web APIs — once a user logs in, the server issues a JWT that the client sends with every subsequent request to prove its identity.
A JWT consists of three Base64URL-encoded parts separated by dots: header.payload.signature
Anatomy of a JWT
- Header: Specifies the token type (
JWT) and signing algorithm (e.g.,HS256,RS256). - Payload: Contains the claims — data about the user and the token (e.g.,
sub,exp,iat, custom roles). - Signature: A cryptographic signature that verifies the token hasn't been tampered with.
Example decoded payload:
{
"sub": "user_123",
"email": "dev@example.com",
"role": "admin",
"iat": 1725000000,
"exp": 1725086400
}
Implementing JWT Authentication (Node.js Example)
1. Issuing a Token on Login
const jwt = require('jsonwebtoken');
function login(req, res) {
const user = authenticateUser(req.body); // your auth logic
if (!user) return res.status(401).json({ error: 'Invalid credentials' });
const token = jwt.sign(
{ sub: user.id, email: user.email, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '1h' }
);
res.json({ token });
}
2. Verifying a Token on Protected Routes
function authenticate(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Missing token' });
}
const token = authHeader.split(' ')[1];
try {
req.user = jwt.verify(token, process.env.JWT_SECRET);
next();
} catch (err) {
res.status(401).json({ error: 'Invalid or expired token' });
}
}
JWT Security Best Practices
- Use strong, random secrets. Your
JWT_SECRETshould be at least 256 bits of randomness. Never hardcode it. - Set short expiry times. Access tokens should expire in minutes to hours, not days. Use refresh tokens for longer sessions.
- Store tokens securely. Prefer
HttpOnlycookies overlocalStorageto mitigate XSS attacks. - Use asymmetric algorithms for distributed systems.
RS256(RSA) allows public key verification without sharing the private signing key. - Validate all claims. Always check
exp(expiry),iat(issued at), andiss(issuer) in your verification logic. - Don't put sensitive data in the payload. JWTs are Base64-encoded, not encrypted. Anyone can decode the payload.
Common JWT Mistakes to Avoid
- Accepting the
nonealgorithm — always explicitly whitelist allowed algorithms in your verify call. - Never revoking tokens — implement a token blacklist or use short-lived tokens with refresh rotation.
- Using the same secret across environments — production, staging, and development should each have unique secrets.
When Not to Use JWTs
JWTs are not always the right tool. For simple session management in a monolithic app with a single server, traditional server-side sessions with a session store (Redis, database) are often simpler and easier to revoke. JWTs shine in distributed systems, microservices, and cross-domain authentication where stateless verification is valuable.