JWT Authentication
Overview
HTTP is stateless. When a user logs in, the server immediately forgets who they are. Historically, servers fixed this by generating a random 'Session ID', giving it to the browser, and saving a copy in the server's RAM. But what if you have 5 load-balanced servers? Server B doesn't share Server A's RAM! JWT (JSON Web Token) solves this. A JWT contains the user's data (like {id: 42}) directly inside the token, mathematically signed by the server's secret key. The server doesn't need to save anything in RAM; it just verifies the cryptographic signature on every request.
Syntax
// npm install jsonwebtoken
const jwt = require('jsonwebtoken');
// --- 1. LOGIN (Creating the Token) ---
app.post('/login', (req, res) => {
// 1. Verify credentials with DB...
// 2. Generate the Token payload
const payload = { userId: 42, role: 'admin' };
// 3. Cryptographically Sign it! (Expires in 1 hour)
const token = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1h' });
// Send it to the frontend!
res.json({ token });
});
// --- 2. PROTECTED ROUTE (Verifying the Token) ---
const requireAuth = (req, res, next) => {
// The frontend sends the token in the 'Authorization' Header
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).send("Missing Token");
try {
// If the token was tampered with, or is expired, this throws an Error!
const decodedPayload = jwt.verify(token, process.env.JWT_SECRET);
// Attach the decrypted data to the request pipeline!
req.user = decodedPayload;
next();
} catch (err) {
res.status(403).send("Invalid or Expired Token");
}
};Common Pitfalls
- Storing sensitive data in the JWT payload. The payload of a JWT is strictly Base64 encoded, NOT ENCRYPTED. Anyone who steals the token (or even just inspects it on the frontend) can easily decode it and read the data. Never put passwords, social security numbers, or credit cards inside a JWT. Only put non-sensitive identifiers (like
user_id). - Using a weak JWT Secret. If your secret is 'secret123', a hacker can easily brute-force the signature locally. Once they find the secret, they can forge their own Admin JWTs and completely compromise your server. Always use a massive, 64-character random string.
Interview Questions
This is the primary architectural flaw of JWTs. You mathematically cannot instantly revoke a stateless JWT. To solve this, companies maintain a 'Blacklist' (usually in a fast Redis cache) of revoked token IDs, effectively turning the JWT back into a stateful system. Alternatively, you use short-lived JWTs (15 mins) and long-lived stateful Refresh Tokens.
Real-World Example
A decoded JWT consists of 3 parts separated by dots: Header.Payload.Signature. The frontend can decode the middle part locally to update the UI (e.g., showing 'Welcome Admin').
// FRONTEND REACT CODE (No secret key needed to decode!)
const token = "eyJhbGc... . eyJ1c2VySWQiOjQyLCJyb2xlIjoiYWRtaW4ifQ . SflKxwRJ...";
// Extract the middle part (Payload) and decode the Base64!
const payloadBase64 = token.split('.')[1];
const user = JSON.parse(atob(payloadBase64));
console.log(user.role); // 'admin'Check Your Knowledge
Test your understanding of JWT Authentication with these quick questions.