Cookies are the backbone of web authentication. Your session token almost certainly lives in a cookie. If that cookie is misconfigured, an attacker can steal it, forge requests with it, or intercept it in transit — without ever cracking your password hashing algorithm or bypassing your authentication logic. Cookie security is foundational.
The Four Critical Cookie Flags
HttpOnly
HttpOnly prevents JavaScript from reading the cookie. Without it, any script running on your page — including injected XSS payloads — can access document.cookie and exfiltrate your session token.
Set-Cookie: session_id=abc123; HttpOnly
With HttpOnly set, document.cookie returns an empty string for that cookie. An XSS attack can still do damage, but it cannot steal the session token directly.
Rule: Every authentication cookie must have HttpOnly. No exceptions.
See our XSS protection guide for how HttpOnly fits into the broader XSS defense strategy.
Secure
The Secure flag restricts the cookie to HTTPS connections only. Without it, the cookie can be transmitted over plain HTTP — making it trivially interceptable on any network path between the user and your server (coffee shop Wi-Fi, compromised routers, etc.).
Set-Cookie: session_id=abc123; HttpOnly; Secure
If your site is HTTPS — and it should be — there is no reason not to set Secure on every authentication cookie.
SameSite
SameSite controls when cookies are sent on cross-site requests. This is your primary defense against Cross-Site Request Forgery (CSRF) attacks.
There are three values:
SameSite=Strict — The cookie is only sent on same-site requests. Cross-site navigation (clicking a link from another site) does not include the cookie. This is the most secure option but can cause friction when users navigate to your site from links in email or other apps.
SameSite=Lax — The cookie is sent on same-site requests and on top-level navigations (clicking a link). Cross-site form POSTs and API calls from other origins do not include the cookie. This is the default in most modern browsers and a good balance for most applications.
SameSite=None — The cookie is sent on all requests, including cross-site. Required for legitimate cross-site use cases (payment widgets, OAuth flows, embedded content). Must be paired with Secure.
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax
Rule: Use Strict for administrative sessions and high-privilege actions. Use Lax as the default for standard sessions. Only use None; Secure when cross-site transmission is genuinely required.
Domain and Path Scoping
Domain controls which subdomains receive the cookie. Setting Domain=yourdomain.com sends the cookie to all subdomains (api.yourdomain.com, admin.yourdomain.com, etc.). Omitting Domain restricts the cookie to exactly the origin that set it.
Path restricts which URL paths receive the cookie. An admin session cookie set with Path=/admin is only sent on requests to /admin/* routes.
Scope cookies as narrowly as your application allows. A cookie scoped to admin.yourdomain.com with Path=/ should not be accessible to www.yourdomain.com.
Cookie Expiry: Session vs Persistent
Session cookies (no Expires or Max-Age) are deleted when the browser session ends. Appropriate for authentication on shared computers.
Persistent cookies (Expires= or Max-Age=) survive browser restarts. Appropriate for "remember me" functionality, but should still have a reasonable maximum lifetime — 30 days is typical. Long-lived session tokens that never rotate increase the window of opportunity for token theft.
Implement server-side session expiry regardless of cookie expiry. The cookie lifetime is a client-side hint, not a security control. Your server should invalidate sessions after inactivity timeout and absolute session lifetime, independent of whether the cookie still exists.
Cookie Prefixes: Browser-Enforced Security
Cookie prefixes are a lesser-known but effective hardening mechanism. Prefixing a cookie name with __Secure- or __Host- causes browsers to enforce additional constraints.
__Secure-: Requires Secure flag and HTTPS.
__Host-: Requires Secure flag, HTTPS, no Domain attribute, and Path=/.
Set-Cookie: __Host-session_id=abc123; HttpOnly; Secure; SameSite=Lax; Path=/
The __Host- prefix is the strongest option for session cookies — it prevents subdomain cookie injection attacks where a compromised subdomain plants a cookie that overrides your main session cookie.
CSRF Protection Beyond SameSite
SameSite=Lax handles most CSRF scenarios but has edge cases. For sensitive actions (password change, payment, account deletion), implement CSRF tokens as an additional layer:
- On page load, generate a random CSRF token and store it server-side in the session
- Include the token in forms as a hidden field and in API requests via a custom header (
X-CSRF-Token) - Validate the token server-side for all state-changing requests
The double-submit cookie pattern is an alternative: set the CSRF token as a non-HttpOnly cookie and require the same value in a request header. Cross-site requests cannot read the cookie (due to SameSite + browser policies) and therefore cannot forge the matching header.
Auditing Your Cookie Configuration
Test your current cookie configuration:
- Open DevTools in your browser → Application → Cookies
- For each authentication cookie, verify the HttpOnly, Secure, and SameSite flags are set
- Check that no sensitive data is stored in non-HttpOnly cookies
- Verify session cookie lifetime is appropriate
Automated tools can scan your site's headers and cookie configuration. WarDek's security scanner flags missing or misconfigured cookie flags as part of its HTTP header and authentication checks — giving you a prioritized list of issues to fix.
Secure Cookie Configuration Checklist
- [ ]
HttpOnlyon all authentication and session cookies - [ ]
Secureon all authentication and session cookies - [ ]
SameSite=LaxorStricton authentication cookies - [ ]
SameSite=None; Secureonly where cross-site is required - [ ]
__Host-prefix on main session cookies - [ ] Session lifetime enforced server-side (not relying on cookie expiry)
- [ ] Session tokens rotated on privilege escalation (login, sudo actions)
- [ ] No sensitive data (PII, payment data) stored in cookies
- [ ] CSRF tokens on state-changing forms (complementary to SameSite)
Cookies are small, but their misconfiguration has large consequences. Most of the fixes above are single-line changes — there is no reasonable justification for leaving session cookies without HttpOnly and Secure on a production site.