How to Secure Your Node.js API with JWT and Cookies
Posted by Nuno Marques on 2 Mar 2025
Introduction
Securing your Node.js API is crucial to protecting user data and preventing unauthorized access. JSON Web Tokens (JWT) combined with Secure HttpOnly Cookies offer a robust authentication strategy. In this guide, we’ll explore how to implement JWT authentication using Secure Cookies and avoid common security pitfalls.
Estimated reading time: 7 minutes
Why JWT and Secure Cookies?
JWTs are widely used for authentication because they allow stateless authentication, reducing the need for session storage. However, storing JWTs in Local Storage is dangerous due to XSS vulnerabilities. Instead, Secure HttpOnly Cookies provide a safer alternative.
Stateless authentication using JWTs
✅ HttpOnly Cookies prevent XSS attacks
✅ Secure attribute ensures data transmission only over HTTPS
✅ SameSite flag helps prevent CSRF attacks
Setting Up JWT Authentication in Node.js
1. Install Dependencies
Start by installing the necessary packages:
npm install express jsonwebtoken cookie-parser dotenv cors
2. Configure Environment Variables
Create a .env
file to store your secret key:
JWT_SECRET=your_strong_secret_key
JWT_EXPIRATION=1h
3. Generate JWT Tokens
const jwt = require("jsonwebtoken");
const generateToken = (userId) => {
return jwt.sign({ id: userId }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRATION,
});
};
4. Set HttpOnly Secure Cookies on Login
const express = require("express");
const cookieParser = require("cookie-parser");
const app = express();
app.use(cookieParser());
app.post("/login", (req, res) => {
const token = generateToken(req.body.userId);
res.cookie("authToken", token, {
httpOnly: true,
secure: true,
sameSite: "Strict",
maxAge: 3600000,
});
res.json({ message: "Login successful" });
});
5. Verify JWT Tokens in Middleware
const verifyToken = (req, res, next) => {
const token = req.cookies.authToken;
if (!token) return res.status(401).json({ message: "Unauthorized" });
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.status(403).json({ message: "Forbidden" });
req.user = user;
next();
});
};
Key Security Considerations
- Avoid Local Storage for JWTs – Use Secure Cookies instead.
- Set
httpOnly
,secure
, andsameSite
attributes for cookies. - Use HTTPS to prevent MITM attacks.
- Implement token expiration and refresh tokens.
- Prevent XSS attacks (Read: Preventing XSS: Best Practices for Frontend Developers)
Next Steps
- Implement CSRF protection strategies.
- Secure API endpoints with role-based authentication.
- Explore OAuth2 for third-party authentication.