Chapter 4: Authentication and Authorization
Chapter 4 of 15
Chapter 4: Authentication and Authorization
4.1 JWT Implementation
JSON Web Tokens (JWT) provide a stateless way to authenticate users and authorize requests.
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
// Login endpoint
app.post('/api/login', async (req, res) => {
const { email, password } = req.body;
// Find user
const user = await User.findOne({ email });
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Verify password
const isValid = await bcrypt.compare(password, user.password_hash);
if (!isValid) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Generate token
const token = jwt.sign(
{ userId: user.id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
res.json({ token, user: { id: user.id, email: user.email } });
});
4.2 JWT Middleware
// Authentication middleware
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) {
return res.status(403).json({ error: 'Invalid or expired token' });
}
req.user = user;
next();
});
}
// Protected route
app.get('/api/profile', authenticateToken, async (req, res) => {
const user = await User.findById(req.user.userId);
res.json(user);
});
4.3 Refresh Tokens
// Generate refresh token
const refreshToken = jwt.sign(
{ userId: user.id },
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: '7d' }
);
// Store refresh token
await RefreshToken.create({
userId: user.id,
token: refreshToken,
expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
});
// Refresh endpoint
app.post('/api/refresh', async (req, res) => {
const { refreshToken } = req.body;
const stored = await RefreshToken.findOne({ token: refreshToken });
if (!stored || stored.expiresAt < new Date()) {
return res.status(403).json({ error: 'Invalid refresh token' });
}
const newAccessToken = jwt.sign(
{ userId: stored.userId },
process.env.JWT_SECRET,
{ expiresIn: '15m' }
);
res.json({ token: newAccessToken });
});
4.4 Role-Based Access Control (RBAC)
// Authorization middleware
function authorize(...roles) {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ error: 'Unauthorized' });
}
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
}
// Usage
app.delete('/api/users/:id',
authenticateToken,
authorize('admin'),
deleteUser
);