Featured image of post Secure Cookie Configuration: A Complete Web Developer Guide Featured image of post Secure Cookie Configuration: A Complete Web Developer Guide

Secure Cookie Configuration: A Complete Web Developer Guide

Complete guide to secure cookie configuration covering SameSite, Secure flag, HttpOnly, cookie prefixes, CHIPS, and cross-site behavior for modern web apps.

Cookies remain one of the most frequently misconfigured security controls on the web. A single missing attribute can expose your application to session hijacking, CSRF, or cross-site information leakage. Modern browsers have pushed stricter defaults, but understanding each attribute and combining them correctly is essential for defense-in-depth.

The core security attributes are Secure, HttpOnly, SameSite, and the __Host- / __Secure- prefixes. Each serves a distinct purpose, and they work best when combined.

SameSite Attribute

SameSite controls when a cookie is sent in cross-site requests. It is the primary defense against CSRF attacks.

Set-Cookie: session=abc123; SameSite=Lax
ValueBehaviorUse Case
StrictSent only for same-site requests (top-level navigation and subresource)CSRF tokens, sensitive account operations
Lax (default)Sent for top-level GET navigations, not cross-site POST, images, scripts, or iframesGeneral session cookies
NoneSent for all cross-site requests; requires Secure flagThird-party widgets, embedded content, API integrations

SameSite=Lax is the default in modern browsers (Chrome, Edge, Firefox) and is appropriate for most session cookies. Use Strict for CSRF tokens and critical operations. Use None only when third-party embedding is required — and always pair it with Secure.


Secure Flag

The Secure attribute ensures the cookie is transmitted only over HTTPS. Without it, a cookie can be intercepted over an unencrypted connection — particularly dangerous on public Wi-Fi.

Set-Cookie: session=abc123; Secure

This flag cannot be set from http:// origins. It must be set from an HTTPS page context. A common mistake is setting Secure on localhost during development (which works) but deploying with mixed content that causes the cookie to be served over HTTP on production.

When using SameSite=None, the Secure flag is mandatory. Browsers reject SameSite=None cookies without Secure.


HttpOnly Attribute

HttpOnly prevents JavaScript access via document.cookie. This is the primary defense against XSS-based session theft. An XSS vulnerability can still execute arbitrary JavaScript, but the attacker cannot read the session cookie directly.

Set-Cookie: session=abc123; HttpOnly

The trade-off is that client-side JavaScript cannot read or write HttpOnly cookies. For SPA authentication flows that inspect cookies, the workaround is to use a dedicated API endpoint that checks authentication status, or use token-based auth stored in memory. Never store session tokens where XSS can reach them if you can avoid it.


Path and Domain Scoping

The Path attribute restricts a cookie to specific URL paths. The Domain attribute controls which subdomains receive the cookie.

Set-Cookie: app_session=xyz; Path=/app; Domain=.example.com

Use Path=/ for site-wide cookies or restrict to specific paths like /admin. The Domain attribute is dangerous when set too broadly. Domain=.example.com makes the cookie accessible to all subdomains, including staging.example.com or dev.example.com — which are often less secure. Only set a broad Domain when subdomain sharing is explicitly required.


Cookie prefixes provide protocol-level guarantees that cannot be bypassed by client-side code.

Set-Cookie: __Host-session=abc123; Secure; Path=/
Set-Cookie: __Secure-csrf=xyz; Secure
PrefixRequirements
__Host-Must be Secure, Path=/, no Domain attribute — scoped to origin
__Secure-Must be Secure — scoped to domain with Secure

Use __Host-session for session tokens. The prefix ensures the cookie is scoped to a single origin, preventing subdomain attacks. The browser enforces these requirements at the protocol level — no JavaScript can strip the prefix.


Size Limits and CHIPS (Partitioned Cookies)

Browsers enforce limits: approximately 4KB per cookie, 50-150 cookies per domain, and 10-50 per origin. Stay within these limits by storing only references (session IDs, resource identifiers) rather than embedding data directly in cookie values.

CHIPS (Cookies Having Independent Partitioned State) introduces the Partitioned attribute. This creates a separate cookie jar per top-level site, preventing cross-site tracking while allowing embedded third-party services to maintain state.

Set-Cookie: widget_pref=dark; Secure; SameSite=None; Partitioned; Path=/

Browser support includes Chrome 114+, Edge 114+, and Opera. CHIPS is ideal for payment iframes, embedded maps, and third-party chat widgets that need state without enabling cross-site tracking.


Cross-Site and Cross-Origin Behavior

Same-site and same-origin are different concepts that affect cookie sending. https://app.example.com and https://api.example.com are same-site (same registrable domain) but cross-origin (different hostnames). SameSite rules are evaluated on site, not origin.

For cross-origin fetch requests to include cookies:

fetch("https://api.example.com/data", {
  credentials: "include",
});

This requires the server to respond with Access-Control-Allow-Credentials: true. Safari’s Intelligent Tracking Prevention (ITP) and Firefox’s Enhanced Tracking Protection (ETP) impose additional restrictions on cookie lifetime and cross-site access, particularly for cookies without user interaction.


Practical Configuration Recipes

// Express.js
app.use(session({
  name: "__Host-session",
  secret: process.env.SESSION_SECRET,
  cookie: {
    secure: true,
    httpOnly: true,
    sameSite: "lax",
    path: "/",
  },
}));
// Next.js API route
export async function GET(request) {
  return new Response(JSON.stringify({ ok: true }), {
    headers: {
      "Set-Cookie":
        "session=abc123; HttpOnly; Secure; SameSite=Lax; Path=/",
    },
  });
}
Cookie TypeConfiguration
AuthenticationHttpOnly; Secure; SameSite=Lax; Path=/
CSRF token__Host-csrf=xyz; Secure; SameSite=Strict; Path=/
Third-party widgetSecure; SameSite=None; Partitioned; Path=/

Testing and Debugging

Browser DevTools (Application tab) shows all cookies, their attributes, and whether they are marked as secure or httpOnly. For command-line testing:

# Check cookie behavior
curl -v -c cookies.txt -b cookies.txt https://example.com/login

The network tab’s response headers show the Set-Cookie header. Check that all expected attributes are present. Use OWASP ZAP or similar tools for automated cookie security scanning as part of your CI pipeline.

Summary

A defense-in-depth cookie strategy combines all available attributes. The default recommendation for most session cookies is HttpOnly + Secure + SameSite=Lax. For CSRF tokens, add the __Host- prefix and SameSite=Strict. Reserve SameSite=None for third-party contexts where it is unavoidable. Regular audits using both browser DevTools and automated scanners ensure your cookie configuration remains secure as browsers evolve their privacy and security defaults.