Skip to content

ExpressJS - Cookies

HTTP cookies are small pieces of data that a server sends to the user’s web browser. The browser stores them and sends them back with every subsequent request to the same server. Cookies are essential for features like session management (tracking logins), personalization (user preferences), and user tracking.

To work with cookies in Express, you need the cookie-parser middleware. It parses the Cookie header on incoming requests and populates req.cookies with an object keyed by the cookie names. It also adds a res.cookie() method to set cookies.

First, install cookie-parser as a dependency:

npm install cookie-parser

Next, import and apply it as middleware in your index.js. It’s important to place it before any routes that need to access cookies.

import express from 'express';
import cookieParser from 'cookie-parser';
const app = express();
// Apply the cookie-parser middleware
// We'll add a secret later for signed cookies
app.use(cookieParser());
// ... your routes

Let’s create two routes: one to set a cookie and another to read it.

// Route to set a cookie
app.get('/set-cookie', (req, res) => {
// Sets a cookie named 'userTheme' with the value 'dark'
res.cookie('userTheme', 'dark');
res.send('Cookie has been set! Check your browser dev tools.');
});
// Route to read the cookie
app.get('/get-cookie', (req, res) => {
// Access the cookies from the request object
const theme = req.cookies.userTheme;
if (theme) {
res.send(`Your theme is set to: ${theme}`);
} else {
res.send('No theme cookie found.');
}
});
// ... app.listen

After running your server, first visit http://localhost:3000/set-cookie. Then, visit http://localhost:3000/get-cookie. You should see the message confirming your theme. You can also inspect the stored cookies in your browser’s developer tools (usually in the Application or Storage tab).

Simply setting a cookie is often not enough for production applications. You must configure them securely to prevent common attacks like Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF).

The res.cookie() method accepts an options object as its third argument. Here are the most important security options:

  • httpOnly: true: This is critical. It prevents the cookie from being accessed by client-side JavaScript (document.cookie). This mitigates XSS attacks where an attacker tries to steal cookies.
  • secure: true: Ensures the cookie is only sent over HTTPS connections. You should always enable this in production.
  • sameSite: 'strict' or 'lax': A powerful defense against CSRF attacks. 'strict' prevents the browser from sending the cookie on any cross-site requests. 'lax' is a reasonable default that allows cookies to be sent on top-level navigation (e.g., clicking a link from another site).
  • maxAge or expires: Sets the cookie’s expiration. maxAge is a time in milliseconds from now, while expires is a specific Date object.
app.get('/set-secure-cookie', (req, res) => {
const options = {
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days in milliseconds
httpOnly: true, // The cookie only accessible by the web server
secure: process.env.NODE_ENV === 'production', // Only set on HTTPS
sameSite: 'lax' // Or 'strict'
};
res.cookie('sessionToken', 'abc123xyz', options);
res.send('Secure cookie set!');
});

Cookies are stored on the client and can be tampered with. To ensure a cookie’s value hasn’t been changed, you can use signed cookies. cookie-parser can do this if you provide it with a secret string.

Important: Your secret should be a long, random string stored securely as an environment variable, not hardcoded.

// Secret should come from an environment variable for security
const COOKIE_SECRET = process.env.COOKIE_SECRET || 'default-secret';
app.use(cookieParser(COOKIE_SECRET));
// Setting a signed cookie
app.get('/set-signed-cookie', (req, res) => {
res.cookie('userRole', 'admin', { signed: true });
res.send('Signed cookie has been set.');
});
// Reading a signed cookie
app.get('/get-signed-cookie', (req, res) => {
// Unsigned cookies are in req.cookies
// Signed cookies are in req.signedCookies
const userRole = req.signedCookies.userRole;
if (userRole) {
res.send(`Your role is: ${userRole}`);
} else {
// This will be the case if the cookie is tampered with or not set
res.status(401).send('Invalid or missing role cookie.');
}
});

To delete a cookie, use res.clearCookie(). You must pass the same options (like domain and path) that you used when setting it.

app.get('/logout', (req, res) => {
res.clearCookie('sessionToken');
res.send('You have been logged out.');
});