A session cookie is a credential. It is the thing that says "this browser is logged in as this person", and anyone who obtains it is that person until it expires. Three attributes decide how well it is protected, and all three are one line of configuration.

Check what a site is setting with the Cookie Security Checker.

Secure

Set-Cookie: session=abc123; Secure

The cookie is only ever sent over HTTPS. Without it, a single plain-HTTP request — a mistyped link, an old bookmark, an image URL somebody hardcoded — sends the session cookie in clear text across the network.

People assume this does not matter on an HTTPS-only site. It does. Your server may redirect HTTP to HTTPS, but the cookie was already transmitted in that first plain request before the redirect happened. The redirect is too late.

There is no reason to omit this on any production site.

HttpOnly

Set-Cookie: session=abc123; Secure; HttpOnly

JavaScript cannot read the cookie — document.cookie simply does not show it. The browser still sends it with every request, so nothing breaks.

This is your damage limitation for cross-site scripting. If an attacker gets script running on your page and your session cookie is HttpOnly, they cannot simply read it and post it to their server. They can still act as the user within that page, which is bad, but they cannot walk away with a credential that works from anywhere.

The only reason to leave it off is if your own JavaScript needs to read that cookie. For a session token, it should not.

SameSite

This one is the CSRF control, and it has three values that behave quite differently.

SameSite=Strict — the cookie is never sent on any cross-site request, including ordinary link clicks. Maximum protection, with a real usability cost: a user following a link to your site from an email arrives logged out, because the cookie was withheld. They log in, and it works from then on. Confusing for them the first time.

SameSite=Lax — sent on top-level navigations using safe methods (clicking a link), withheld on cross-site POSTs, iframes and background requests. This blocks the classic CSRF pattern while keeping links working. It is the right default for most sessions, and it is what browsers now assume when the attribute is missing.

SameSite=None — always sent. Required for genuine cross-site use such as an embedded widget or a third-party SSO flow. Browsers require it to be paired with Secure, and setting None without Secure means the cookie is rejected entirely — which produces a baffling "my login just stopped working" bug.

The attributes people forget

Domain — leave it off unless you need the cookie shared across subdomains. Setting Domain=example.com sends the cookie to every subdomain, including any you do not control tightly. A forgotten staging or marketing subdomain becomes a route to your session cookies.

Path — mild scoping. Not a security boundary; do not rely on it.

Max-Age / Expires — a session cookie with no expiry dies when the browser closes, which is usually what you want for authentication. A "remember me" cookie that lasts a year is a decision worth making deliberately rather than by default.

A correct session cookie

Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Lax; Path=/

That is it. Three attributes and a path. If your session cookie looks like that, this whole class of problem is handled.

For a cookie that must work inside a third-party iframe:

Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=None; Path=/

And in that case your CSRF protection has to come from tokens instead, because SameSite is no longer doing that job.

What flags do not fix

These attributes protect the cookie in transit and at rest in the browser. They say nothing about what is inside it.

A predictable session identifier is still guessable with every flag set. A session that never expires server-side is still valid forever. And if your application does not invalidate sessions on logout or password change, a stolen cookie keeps working regardless of how carefully it was transmitted.

Checking a site

  1. Run it through the Cookie Security Checker, or open DevTools and read the Application tab.
  2. Find the session cookie — usually the one with a random-looking value.
  3. Confirm Secure and HttpOnly are both set.
  4. Confirm SameSite is Lax or Strict, and that any None is paired with Secure.
  5. Check whether Domain is set more broadly than it needs to be.

Common questions

Does HttpOnly stop XSS?
No. It limits the damage. An attacker with script execution can still act as the user in that page; they just cannot steal the cookie for use elsewhere.

Strict or Lax?
Lax for almost everything. Strict logs users out when they arrive from an external link, which is usually not worth the trade.

Why did my cookie stop working after I set SameSite=None?
Because None requires Secure. Without it the browser rejects the cookie outright.

Do I need Secure if my site is HTTPS-only?
Yes. A single plain-HTTP request transmits the cookie before your redirect can intervene.

Where to go next