TL;DR
Cookie security depends on proper attributes: HttpOnly prevents XSS access, Secure ensures HTTPS-only, SameSite prevents CSRF. Most session cookies should have all three. These prompts help you audit your cookies and set them up correctly.
Cookie Security Audit
Audit all cookies my application sets for security issues.
For each cookie, check:
- HttpOnly: Is it set? (Required for auth cookies)
- Secure: Is it set? (Required for production)
- SameSite: What value? (Lax minimum for auth)
- Domain: Is it properly scoped?
- Path: Is it properly scoped?
- Max-Age/Expires: Appropriate lifetime?
Find all places cookies are set:
- res.cookie() calls
- Set-Cookie headers
- document.cookie assignments
- Framework session configuration
Flag issues:
- Session/auth cookies without HttpOnly
- Any cookie without Secure in production
- SameSite=None without Secure
- Overly broad Domain scope
- Very long expiration for session cookies
Secure Session Cookie
Configure my session cookie with proper security attributes.
Framework: Next.js/Express/Django
Recommended settings: Set-Cookie: session=value; HttpOnly; Secure; SameSite=Lax; Path=/
Express example: res.cookie('session', sessionId, { httpOnly: true, // Not accessible via JavaScript secure: true, // HTTPS only sameSite: 'lax', // CSRF protection path: '/', // Available site-wide maxAge: 24 * 60 * 60 * 1000, // 24 hours // domain: omit unless needed for subdomains });
For development (HTTP localhost): secure: process.env.NODE_ENV === 'production'
Note: SameSite=Strict breaks OAuth flows SameSite=Lax is usually the right choice
HttpOnly is essential for auth cookies: Without it, any XSS on your site can steal session cookies. It's the difference between XSS being annoying and XSS being a full account takeover.
SameSite Attribute Guide
Choose the right SameSite value for my cookies.
SameSite options:
Strict:
- Cookie only sent for same-site requests
- Most secure but can break legitimate flows
- User clicking link from email won't be logged in
- Use for: high-security banking, admin panels
Lax (Recommended default):
- Sent for same-site + top-level navigation
- Good balance of security and usability
- User clicking link from email stays logged in
- Use for: most session cookies
None:
- Sent with all requests (cross-site too)
- Must be used with Secure
- Needed for: cross-site iframes, third-party contexts
- Use sparingly and only when required
Examples: // Standard session sameSite: 'lax'
// Admin session (extra security) sameSite: 'strict'
// Third-party widget that needs auth sameSite: 'none', secure: true
Cookie Prefixes
Use cookie prefixes for additional security enforcement.
Cookie prefixes tell browsers to require certain attributes:
__Secure- prefix:
- Cookie must have Secure attribute
- Must be set over HTTPS Set-Cookie: __Secure-session=value; Secure; ...
__Host- prefix (strictest):
- Must have Secure attribute
- Must NOT have Domain attribute
- Path must be /
- Prevents subdomain attacks Set-Cookie: __Host-session=value; Secure; Path=/
Using __Host- prefix: res.cookie('__Host-session', value, { httpOnly: true, secure: true, sameSite: 'lax', path: '/' // No domain attribute! });
Benefits:
- Browser enforces security even if code has bugs
- __Host- prevents subdomain cookie injection attacks
- Defense in depth
Pro tip: Test your cookies at https://securityheaders.com or in browser DevTools (Application > Cookies). You can see all attributes and quickly spot missing security flags.
Why doesn't my cookie work in development?
Secure cookies only work over HTTPS. For localhost development, either use HTTPS (mkcert), or conditionally disable Secure in dev (but always enable in production).
My OAuth login broke after adding SameSite. What do I do?
OAuth redirects are cross-site. Use SameSite=Lax (not Strict) which allows cookies on top-level navigations. If using iframes for auth, you may need SameSite=None with Secure.