Lesson 19 / 23
JWT-based Auth
Login issues a token; a middleware guards protected routes.
The flow
- client sends credentials to
/login. 2) server verifies and signs a JWT. 3) client sends that token on every future request. 4) a middleware verifies it before allowing access.
Login route
On success, sign a token carrying the user id and an expiry.
import jwt from 'jsonwebtoken';
app.post('/login', express.json(), async (req, res) => {
const { email, password } = req.body;
const user = await verifyCredentials(email, password); // your own check
if (!user) return res.status(401).json({ error: 'Invalid credentials' });
const token = jwt.sign({ sub: user.id }, process.env.JWT_SECRET, { expiresIn: '1h' });
res.json({ token });
});Protecting a route
Read the Authorization: Bearer <token> header, verify it, attach the user, then continue.
function requireAuth(req, res, next) {
const header = req.headers.authorization || '';
const token = header.startsWith('Bearer ') ? header.slice(7) : null;
if (!token) return res.status(401).json({ error: 'No token provided' });
try {
req.user = jwt.verify(token, process.env.JWT_SECRET);
next();
} catch {
res.status(401).json({ error: 'Invalid or expired token' });
}
}
app.get('/me', requireAuth, (req, res) => {
res.json({ userId: req.user.sub });
});Keep the secret secret
Never hardcode JWT_SECRET — load it from an environment variable, and always serve auth traffic over HTTPS.