Securing APIs with Express.js and JSON Web Tokens
A Comprehensive Guide to API Authentication and Authorization
Securing APIs with Express.js and JSON Web Tokens (JWT)
- Express and JWT
- Concepts
- Express.js auth middleware
Express.js middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. Authentication middleware checks if a user is authenticated and authorized to access a particular route. If not, it sends an appropriate response (like 401 Unauthorized). It typically uses JWTs to verify the user's identity.
const express = require('express'); const jwt = require('jsonwebtoken'); const app = express(); app.use((req, res, next) => { const token = req.headers.authorization; if (token) { jwt.verify(token, 'your-secret-key', (err, decoded) => { if (err) return res.sendStatus(403); req.user = decoded; next(); }); } else { res.sendStatus(401); } }); app.get('/profile', (req, res) => { res.json({ message: `Welcome ${req.user.username}` }); });
- JSON Web Tokens (JWT)
JSON Web Tokens are an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. JWTs are digitally signed to prevent tampering and contain a payload with claims (statements about an entity or entities).
Structure: A JWT consists of three parts separated by dots (.).
- Header: Contains metadata like the signing algorithm (e.g., HS256).
- Payload: Contains the claims (e.g., user ID, username, expiration time).
- Signature: Used to verify the integrity of the token.
- Express.js auth middleware
- Implementation
- Setting up Express.js
First, install necessary packages:
npm install express jsonwebtoken
Then, create an Express.js app:
const express = require('express'); const app = express(); app.use(express.json()); // for parsing JSON bodies
- Generating JWTs
Use the
jsonwebtoken
library to generate a JWT. This usually involves encoding a payload containing user information.const jwt = require('jsonwebtoken'); const createToken = (user) => { const token = jwt.sign({ userId: user.id, username: user.username }, 'your-secret-key', { expiresIn: '1h' }); return token; };
- Verifying JWTs
When a request arrives, verify the token's signature and extract the payload to check user permissions.
const jwt = require('jsonwebtoken'); const verifyToken = (token) => { try { const decoded = jwt.verify(token, 'your-secret-key'); return decoded; } catch (error) { return null; } };
- Protecting Routes
Use middleware to protect routes that require authentication:
app.get('/profile', verifyToken, (req, res) => { res.json({ user: req.user }); });
- Setting up Express.js
- Examples
- Creating a simple login API
A simple login API would take username and password, verify them against a database, and if successful, generate and return a JWT.
app.post('/login', (req, res) => { const { username, password } = req.body; // ... (database verification) if (verified) { const token = createToken({ id: user.id, username: user.username }); res.json({ token }); } else { res.status(401).json({ error: 'Invalid credentials' }); } });
- Protecting API endpoints
Any route after the middleware that requires authentication should perform actions only after JWT verification.
app.get('/admin', verifyToken, (req, res) => { // ... only accessible if token is valid res.json({ message: 'Admin page' }); });
- Creating a simple login API
- Explanation
- Authentication vs. Authorization
Authentication verifies the user's identity (who they are). Authorization determines what the user is allowed to do (permissions).
- JWT structure
A JWT typically has a header, a payload, and a signature. The payload holds user information while the signature verifies integrity.
- Security considerations
Always use strong, randomly generated secrets. Keep secrets out of version control. Use HTTPS to protect JWTs in transit. Set short expiration times for tokens. Consider using a refresh token mechanism for long-lived sessions.
Important Note: Never store sensitive data directly in JWTs. Only include essential data required for authorization.
- Authentication vs. Authorization
- Concepts