Skip to content

Cookies

Cookie flags explained: Secure, HttpOnly and SameSite

What the Secure, HttpOnly and SameSite cookie flags do, which cookies need them, and copy-paste Set-Cookie examples for common stacks.

By SurfaceWatch··5 min read

A session cookie is the key to a user's logged-in account. Anyone who gets a copy of it can act as that user, with no password needed. Three small flags on the Set-Cookie header decide how easy it is to steal or misuse that cookie. Most frameworks set them only if you ask.

Secure: only over HTTPS

A cookie with the Secure flag is only ever sent over HTTPS. Without it, the browser can send the cookie over plain HTTP too, for example on a first visit before a redirect, where anyone on the same network can read it.

HttpOnly: invisible to JavaScript

A cookie with HttpOnly can't be read by scripts on the page (document.cookie doesn't show it). If an attacker manages to inject a script through an XSS bug, they can't just copy your session cookie. Use it on every cookie that JavaScript doesn't need to read, session cookies above all.

SameSite: stop cross-site requests

SameSite controls whether the browser attaches the cookie to requests that start on another site, which is how cross-site request forgery (CSRF) works.

  • Strict: the cookie is never sent on cross-site requests. Safest, but a user arriving from a link on another site appears logged out on the first page.
  • Lax: sent on normal link clicks (top-level navigations) but not on embedded or POST requests from other sites. A good default for most login cookies, and what current browsers assume if you don't say.
  • None: sent everywhere. Needed for real cross-site use such as embedded widgets, and only valid together with Secure.

Putting it together

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

Express

res.cookie('sessionid', token, { secure: true, httpOnly: true, sameSite: 'lax' });

PHP

session_set_cookie_params(['secure' => true, 'httponly' => true, 'samesite' => 'Lax']);

Django (settings.py)

SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'

Which cookies need them?

Any cookie that identifies a logged-in user (session, auth tokens) needs all three. Analytics and advertising cookies are set by third parties, so you usually can't change their flags. A good checker should separate the cookies you can fix from the ones you can't.

How to check your site

In Chrome's DevTools, open Application, then Cookies, and look at the Secure, HttpOnly and SameSite columns. Or let SurfaceWatch do it: it reads your site's cookies, flags session cookies that are missing a flag.

Three flags, one line of config. Set them on every session cookie, and a stolen or forged request gets a lot harder.

Keep reading

Check your site's cookies — add SurfaceWatch free

One click, an honest grade, and the exact fix. Free to install. No account needed.