JWT Authentication in Express
Imagine you have a VIP pass to a concert. The pass has your name, photo, and a hologram that proves it's authentic. You don't need to talk to the ticket counter every time you just show your pass at different entry points. JWT (JSON Web Token) works exactly like this VIP pass in web applications.
What is JWT?
JWT (JSON Web Token) is an open standard for securely transmitting information between parties as a JSON object. It's compact, URL-safe, and digitally signed, so it can be verified and trusted. JWTs are commonly used for authentication and information exchange.
JWT Structure
A JWT consists of three parts separated by dots:
- Header Contains the token type and signing algorithm (e.g., HS256).
- Payload Contains the claims (user data, expiration time, etc.).
- Signature Used to verify the token hasn't been tampered with.
Example:
xxxxx.yyyyy.zzzzzHow JWT Authentication Works
- User logs in with email and password.
- Server verifies credentials and creates a JWT containing user information (like userId).
- Server sends the JWT back to the client.
- Client stores the JWT (usually in localStorage or cookie).
- On subsequent requests, client sends the JWT in the Authorization header.
- Server verifies the JWT and extracts user information.
Installing JWT
npm install jsonwebtokenComplete JWT Authentication Example
const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const app = express();
app.use(express.json());
// Secret key for signing tokens (store in environment variables!)
const JWT_SECRET = 'your-super-secret-key-change-this';
// Mock database
const users = [];
// Helper function to generate token
const generateToken = (userId) => {
return jwt.sign({ userId }, JWT_SECRET, { expiresIn: '7d' });
};
// Middleware to verify token
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
jwt.verify(token, JWT_SECRET, (err, decoded) => {
if (err) {
return res.status(403).json({ error: 'Invalid or expired token' });
}
req.userId = decoded.userId;
next();
});
};
// Register endpoint
app.post('/register', async (req, res) => {
try {
const { email, password } = req.body;
// Check if user already exists
if (users.find(u => u.email === email)) {
return res.status(400).json({ error: 'User already exists' });
}
// Hash password
const hashedPassword = await bcrypt.hash(password, 10);
// Create user
const newUser = {
id: users.length + 1,
email,
password: hashedPassword
};
users.push(newUser);
// Generate token
const token = generateToken(newUser.id);
res.status(201).json({
message: 'User created successfully',
token,
user: { id: newUser.id, email: newUser.email }
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Login endpoint
app.post('/login', async (req, res) => {
try {
const { email, password } = req.body;
// Find user
const user = users.find(u => u.email === email);
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Verify password
const validPassword = await bcrypt.compare(password, user.password);
if (!validPassword) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Generate token
const token = generateToken(user.id);
res.json({
message: 'Login successful',
token,
user: { id: user.id, email: user.email }
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Protected route example
app.get('/profile', authenticateToken, async (req, res) => {
const user = users.find(u => u.id === req.userId);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json({
id: user.id,
email: user.email
});
});
// Another protected route
app.get('/dashboard', authenticateToken, (req, res) => {
res.json({ message: `Welcome to your dashboard! Your user ID is ${req.userId}` });
});JWT Best Practices
- Keep it secret Store JWT_SECRET in environment variables, never in code.
- Set expiration Always set expiresIn to limit token lifetime.
- Use HTTPS Always transmit tokens over HTTPS.
- Store tokens securely On client, store in HttpOnly cookies for web apps, or secure storage for mobile.
- Keep payload small Don't store sensitive data in payload (it's base64 encoded, not encrypted).
- Implement token refresh Use refresh tokens for better security.
Two Minute Drill
- JWT is a stateless authentication token containing user claims.
- Client sends JWT in Authorization header:
Bearer <token>. - Server verifies token with
jwt.verify(). - Create middleware to protect routes.
- Always use strong secrets, set expiration, and use HTTPS.
- JWT is perfect for REST APIs and microservices.
Need more clarification?
Drop us an email at career@quipoinfotech.com
