HTTP cookies (or simply cookies) are small pieces of data that a server sends to a user's web browser. The browser may store them and send them back with later requests to the same server. They are a fundamental part of the modern web, enabling essential features like session management, personalization, and user tracking.
The process begins when a server wants to store information on the client. It includes a Set-Cookie
header in its HTTP response. The browser receives this response, stores the cookie, and then includes a Cookie
header in all subsequent HTTP requests to that same server.
This flow allows the server to maintain a "memory" of the user across multiple requests, which are otherwise stateless.
Here’s a visual representation of the cookie flow:
Set-Cookie
: The server responds with the requested resource and includes a Set-Cookie
header. For example: Set-Cookie: user_id=12345;
.Cookie
: For every subsequent request to the same server, the browser automatically includes the Cookie
header with the stored value. For example: Cookie: user_id=12345;
.A cookie isn't just a simple key-value pair. It has several attributes that control its behavior, lifetime, and security. These are set by the server in the Set-Cookie
header.
Here are the most important attributes:
Attribute | Purpose | Details / Values |
---|---|---|
Expires Max-Age | Controls cookie lifetime |
Expires: Sets a specific expiration date/time. Max-Age: Sets duration in seconds from set time. If both are set, Max-Age takes precedence. If neither, cookie is a session cookie (deleted when browser closes). |
Domain | Specifies which hosts receive the cookie | Defaults to the host that set the cookie. Not sent to subdomains unless specified. |
Path | Scopes cookie to a URL path |
E.g., Path=/app means cookie sent only for /app and its subdirectories.
|
Secure | Restricts cookie to HTTPS | Cookie sent only over encrypted (HTTPS) connections. |
HttpOnly | Prevents JS access |
Not accessible via document.cookie in JavaScript. Helps prevent XSS attacks.
|
SameSite | CSRF protection |
Controls cross-site sending: Strict: Only sent with same-site requests. Lax: (Default) Sent with same-site and top-level GET navigations. None: Sent with all requests (must also set Secure). |
You can interact with non-HttpOnly
cookies using JavaScript through the document.cookie
property.
To create a cookie, you assign a string to document.cookie
that includes the key-value pair and any desired attributes.
// Basic cookie document.cookie = "username=JohnDoe"; // Cookie with expiration and path const expirationDate = new Date(); expirationDate.setDate(expirationDate.getDate() + 7); // Expires in 7 days document.cookie = `theme=dark; expires=${expirationDate.toUTCString()}; path=/`;
document.cookie
returns a single string containing all cookies for the current document, separated by semicolons. You need to parse this string to get a specific value.
function getCookie(name) { const cookies = document.cookie.split(';').map(cookie => cookie.trim()); for (const cookie of cookies) { const [cookieName, cookieValue] = cookie.split('='); if (cookieName === name) { return decodeURIComponent(cookieValue); } } return null; } const username = getCookie('username'); // "JohnDoe"
To delete a cookie, you set its Expires
attribute to a past date.
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
Managing cookies on the server is more robust and secure, especially with the HttpOnly
attribute. Here’s how to do it in Node.js using the popular cookie-parser
middleware for Express.
First, install the necessary packages:
npm install express cookie-parser
The res.cookie()
method makes it easy to set cookies and their attributes.
const express = require('express'); const cookieParser = require('cookie-parser'); const app = express(); app.use(cookieParser()); app.get('/login', (req, res) => { // Set a simple cookie res.cookie('username', 'JohnDoe', { maxAge: 900000, httpOnly: true }); // Set a secure, SameSite cookie for sensitive data res.cookie('session_id', 'xyz789', { maxAge: 86400000, // 24 hours httpOnly: true, secure: true, // Only send over HTTPS sameSite: 'Strict' }); res.send('Cookies have been set!'); }); app.listen(3000, () => console.log('Server running on port 3000'));
app.get('/profile', (req, res) => { const username = req.cookies.username; if (username) { res.send(`Welcome back, ${username}!`); } else { res.send('Please log in.'); } });
The res.clearCookie()
method deletes a cookie by its name.
app.get('/logout', (req, res) => { res.clearCookie('username'); res.clearCookie('session_id'); res.send('Logged out successfully.'); });
Spring Boot provides excellent, built-in support for handling cookies via the HttpServletRequest
and HttpServletResponse
objects, or more elegantly with @CookieValue
annotations.
You create a Cookie
object and add it to the HttpServletResponse
.
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; @RestController public class CookieController { @GetMapping("/login") public String setCookie(HttpServletResponse response) { // Create a cookie Cookie userCookie = new Cookie("username", "JaneDoe"); userCookie.setMaxAge(7 * 24 * 60 * 60); // 7 days userCookie.setHttpOnly(true); userCookie.setPath("/"); // Global cookie // Create a secure cookie for session Cookie sessionCookie = new Cookie("session_id", "abc456"); sessionCookie.setMaxAge(24 * 60 * 60); // 24 hours sessionCookie.setHttpOnly(true); sessionCookie.setSecure(true); // Requires HTTPS // In Spring, SameSite is configured globally or via HttpHeaders // Add cookies to the response response.addCookie(userCookie); response.addCookie(sessionCookie); return "Cookies have been set!"; } }
The easiest way to read a cookie in a Spring controller is with the @CookieValue
annotation.
import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ProfileController { @GetMapping("/profile") public String readCookie( @CookieValue(name = "username", defaultValue = "Guest") String username) { return "Welcome back, " + username + "!"; } }
To delete a cookie, you create a cookie with the same name and set its maxAge
to 0.
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; @RestController public class LogoutController { @GetMapping("/logout") public String deleteCookie(HttpServletResponse response) { Cookie cookie = new Cookie("username", null); // value can be null cookie.setMaxAge(0); // 0 seconds cookie.setPath("/"); response.addCookie(cookie); return "Logged out successfully."; } }
Next.js provides powerful built-in utilities for handling cookies on both the client and server side.
Use the cookies()
function from next/headers
to set cookies in server components or API routes.
import { cookies } from 'next/headers'; // In a Server Component or API Route export async function POST(request: Request) { const cookieStore = cookies(); // Set a simple cookie cookieStore.set('username', 'JohnDoe', { maxAge: 7 * 24 * 60 * 60, // 7 days httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'strict', path: '/' }); // Set a session cookie cookieStore.set('session_id', 'xyz789', { maxAge: 24 * 60 * 60, // 24 hours httpOnly: true, secure: true, sameSite: 'strict' }); return Response.json({ message: 'Cookies set successfully' }); }
Access cookies directly in server components using the cookies()
function.
import { cookies } from 'next/headers'; export default async function ProfilePage() { const cookieStore = cookies(); const username = cookieStore.get('username')?.value || 'Guest'; const sessionId = cookieStore.get('session_id')?.value; return ( <div> <h1>Welcome back, {username}!</h1> {sessionId && <p>Session ID: {sessionId}</p>} </div> ); }
Cookies are a cornerstone of modern web development, enabling stateful interactions over the stateless HTTP protocol. While client-side manipulation is possible, best practices dictate that cookies, especially those containing sensitive information, should be managed on the server with the HttpOnly
, Secure
, and SameSite
attributes to enhance security.
For more in-depth tutorials on modern software development practices, follow me for more content:
🔗 Blog 🔗 YouTube 🔗 LinkedIn 🔗 Medium 🔗 Github
Stay tuned for more content on the latest in AI and software engineering!
Understanding and configuring CORS in a Java Spring backend.
Explore the evolution of the HTTP protocol, comparing HTTP/0.9, HTTP/1.0, HTTP/1.1, HTTP/2, and HTTP/3. Understand their improvements, drawbacks, and use cases.
Get instant AI-powered summaries of YouTube videos and websites. Save time while enhancing your learning experience.