Express Cookie Handling
Cookies are small pieces of data that a server sends to a user's web browser. The browser may store these cookies and send them back to the server in subsequent requests. In web development, cookies serve various purposes, including session management, tracking user preferences, and implementing authentication systems.
In this guide, we'll explore how to handle cookies in Express.js applications effectively and securely.
Prerequisites
Before diving into cookie handling in Express, you should have:
- Basic knowledge of Node.js and Express.js
- A working Express.js application set up
- Understanding of HTTP requests and responses
Installing the Cookie Parser Middleware
Express doesn't have built-in cookie handling, but it offers a middleware called cookie-parser
that simplifies working with cookies. Let's start by installing it:
npm install cookie-parser
Setting Up Cookie Parser Middleware
Once installed, you need to set up the cookie-parser middleware in your Express application:
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
// Set up cookie parser middleware
app.use(cookieParser());
// Optional: You can provide a secret key for signed cookies
// app.use(cookieParser('your-secret-key'));
Setting Cookies
To set a cookie in an Express application, you use the res.cookie()
method:
app.get('/set-cookie', (req, res) => {
// Set a simple cookie
res.cookie('username', 'john_doe');
res.send('Cookie has been set!');
});
Setting Cookies with Options
You can provide various options when setting cookies:
app.get('/set-cookie-with-options', (req, res) => {
// Set cookie with options
res.cookie('user_preferences', JSON.stringify({ theme: 'dark', fontSize: 'large' }), {
maxAge: 24 * 60 * 60 * 1000, // 24 hours in milliseconds
httpOnly: true, // Cookie is not accessible via JavaScript
secure: true, // Cookie only sent over HTTPS
sameSite: 'strict' // Helps prevent CSRF attacks
});
res.send('Cookie with options has been set!');
});
Common Cookie Options
Here are some important cookie options you can use:
Option | Description |
---|---|
maxAge | Maximum age of the cookie in milliseconds |
expires | Specific date when the cookie expires |
httpOnly | If true, cookie cannot be accessed by client-side JavaScript |
secure | If true, cookie is only sent over HTTPS |
domain | Domain for which the cookie is valid |
path | Path for which the cookie is valid |
sameSite | Controls when cookies are sent with cross-site requests (strict, lax, or none) |
Reading Cookies
To read cookies that have been sent by the client, use the req.cookies
object:
app.get('/get-cookies', (req, res) => {
const username = req.cookies.username;
if (username) {
res.send(`Hello, ${username}!`);
} else {
res.send('No username cookie found.');
}
});
Reading All Cookies
You can access all cookies sent by the client:
app.get('/all-cookies', (req, res) => {
res.json(req.cookies);
});
Signed Cookies
For additional security, you can use signed cookies, which are cookies that have been signed with a secret key to prevent tampering:
const app = express();
app.use(cookieParser('my-secret-key'));
// Setting a signed cookie
app.get('/set-signed-cookie', (req, res) => {
res.cookie('user_id', '12345', { signed: true });
res.send('Signed cookie set!');
});
// Reading a signed cookie
app.get('/get-signed-cookie', (req, res) => {
const userId = req.signedCookies.user_id;
if (userId) {
res.send(`User ID: ${userId}`);
} else {
res.send('No signed user ID cookie found.');
}
});
Clearing Cookies
To remove a cookie, use the res.clearCookie()
method:
app.get('/clear-cookie', (req, res) => {
res.clearCookie('username');
res.send('Username cookie cleared!');
});
If the cookie was set with specific options like path
or domain
, you need to include the same options when clearing it:
app.get('/clear-specific-cookie', (req, res) => {
res.clearCookie('user_preferences', {
path: '/',
domain: 'example.com'
});
res.send('User preferences cookie cleared!');
});
Practical Example: User Theme Preference
Let's build a simple example that uses cookies to remember a user's theme preference:
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
app.use(express.urlencoded({ extended: true }));
// Serve an HTML form for selecting theme
app.get('/', (req, res) => {
const currentTheme = req.cookies.theme || 'light';
res.send(`
<html>
<head>
<title>Theme Selector</title>
<style>
body {
background-color: ${currentTheme === 'dark' ? '#333' : '#fff'};
color: ${currentTheme === 'dark' ? '#fff' : '#333'};
font-family: Arial, sans-serif;
padding: 20px;
}
</style>
</head>
<body>
<h1>Select Your Theme</h1>
<form action="/set-theme" method="post">
<select name="theme">
<option value="light" ${currentTheme === 'light' ? 'selected' : ''}>Light</option>
<option value="dark" ${currentTheme === 'dark' ? 'selected' : ''}>Dark</option>
</select>
<button type="submit">Save Preference</button>
</form>
<p>Your current theme is: ${currentTheme}</p>
</body>
</html>
`);
});
// Set the theme cookie based on form submission
app.post('/set-theme', (req, res) => {
const { theme } = req.body;
// Set cookie that expires in 30 days
res.cookie('theme', theme, {
maxAge: 30 * 24 * 60 * 60 * 1000,
httpOnly: true
});
res.redirect('/');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
Practical Example: Simple Authentication System
Here's a basic example of using cookies for authentication:
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser('auth-secret'));
app.use(express.urlencoded({ extended: true }));
// Fake user database
const users = {
'user1': 'password1',
'user2': 'password2'
};
// Middleware to check if user is logged in
function isAuthenticated(req, res, next) {
const username = req.signedCookies.username;
if (username && users[username]) {
next();
} else {
res.redirect('/login');
}
}
// Login page
app.get('/login', (req, res) => {
res.send(`
<h1>Login</h1>
<form method="post" action="/login">
<div>
<label>Username:</label>
<input type="text" name="username">
</div>
<div>
<label>Password:</label>
<input type="password" name="password">
</div>
<button type="submit">Login</button>
</form>
`);
});
// Process login
app.post('/login', (req, res) => {
const { username, password } = req.body;
if (users[username] && users[username] === password) {
// Set a signed cookie on successful login
res.cookie('username', username, {
signed: true,
httpOnly: true,
maxAge: 3600000 // 1 hour
});
res.redirect('/dashboard');
} else {
res.send('Invalid username or password. <a href="/login">Try again</a>');
}
});
// Dashboard (protected route)
app.get('/dashboard', isAuthenticated, (req, res) => {
const username = req.signedCookies.username;
res.send(`
<h1>Welcome to your dashboard, ${username}!</h1>
<p>This is a protected route that requires authentication.</p>
<a href="/logout">Logout</a>
`);
});
// Logout
app.get('/logout', (req, res) => {
res.clearCookie('username');
res.redirect('/login');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
Best Practices for Cookie Security
-
Use the
httpOnly
flag to prevent client-side JavaScript from accessing the cookie, reducing XSS risks. -
Use the
secure
flag to ensure cookies are only sent over HTTPS connections. -
Implement
sameSite
attribute to control when cookies are sent with cross-site requests:strict
: Cookies are only sent in first-party contextlax
: Cookies are sent when the user navigates to the site from an external linknone
: Cookies are sent on both same-site and cross-site requests (requiressecure: true
)
-
Set appropriate expiration with
maxAge
orexpires
to limit the cookie's lifespan. -
Use signed cookies for any sensitive information to prevent tampering.
-
Keep cookie data minimal - store only what's necessary.
Cookie Limitations
Be aware of these limitations when working with cookies:
-
Size limit: Browsers typically limit cookies to 4KB per domain.
-
Number limit: Most browsers limit the number of cookies per domain (usually around 50).
-
Privacy concerns: Due to regulations like GDPR and CCPA, you may need to get user consent for non-essential cookies.
Summary
In this guide, we've learned how to:
- Set up the cookie-parser middleware in Express
- Set cookies with various options
- Read cookies sent by clients
- Use signed cookies for added security
- Clear cookies when they're no longer needed
- Implement practical examples like theme preferences and simple authentication
- Follow best practices for cookie security
Cookies are a fundamental part of web applications, but they should be used responsibly with security and privacy in mind. For more complex state management needs, consider using sessions or other state management solutions.
Additional Resources
- Express.js Documentation
- cookie-parser on npm
- MDN Web Docs: HTTP cookies
- OWASP: Session Management Cheat Sheet
Exercises
- Modify the theme preference example to include more theme options.
- Build a shopping cart system that stores cart items in cookies.
- Create a "remember me" feature for the authentication example.
- Implement a cookie consent banner that complies with privacy regulations.
- Extend the authentication system to have different user roles with different access levels.
Happy coding!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)