HttpOnly, Secure, and SameSite Cookies Explained (What They Actually Do)
Cookies have three security-relevant flags that get mentioned together often enough that it's easy to conflate what each one actually protects against — but they defend against three genuinely different attack categories, and setting only one or two while assuming you're covered on all fronts is a common, avoidable gap.
HttpOnly prevents JavaScript running on the page from reading the cookie's value at all, via document.cookie or any other client-side API. This is specifically a defense against cross-site scripting (XSS) — if an attacker manages to run malicious JavaScript on your page, an HttpOnly cookie still can't be read and exfiltrated by that script, even though the script is running in the same page context.
Secure means the cookie is only ever sent over an HTTPS connection, never over plain HTTP. Without this flag, a cookie set on a site that's accessible over both HTTP and HTTPS could be intercepted by anyone able to observe unencrypted network traffic — a genuinely realistic threat on public WiFi, for example — even if your site is normally served over HTTPS, since a single accidental HTTP request would expose it.
SameSite controls whether the cookie gets sent along with requests originating from a different site than the one that set it, and it defends against cross-site request forgery (CSRF) — an attack where a malicious site tries to trigger a request to your site using the victim's existing authenticated session, relying on the browser automatically attaching cookies to that cross-site request. SameSite=Strict blocks the cookie from being sent in essentially all cross-site contexts; SameSite=Lax (the modern browser default) allows it for safe top-level navigation like clicking a link, but blocks it for things like cross-site form submissions and image or script requests.
It's worth being clear that these three flags protect against three different attacks, not overlapping variations of the same one — a cookie with HttpOnly but no SameSite setting is still vulnerable to CSRF, and a cookie with SameSite=Strict but no HttpOnly flag is still readable by any JavaScript that manages to execute on the page via XSS. For a session or authentication cookie, you generally want all three flags set together, not just whichever one addresses the threat you happened to think of first.
SameSite=None is a valid setting for legitimate cross-site use cases — an embedded widget or iframe that genuinely needs its cookie sent in a cross-site context — but browsers require the Secure flag to be set whenever SameSite=None is used, and using None without a real cross-site requirement unnecessarily widens your CSRF exposure for no benefit.
When you're setting authentication or session cookies from a server, explicitly setting all three flags — rather than relying on framework or browser defaults, which vary and change over time — is worth the extra line of configuration, since the specific combination genuinely matters for what protection you actually end up with in production.
Found this helpful?
SyncTonight's tools and guides are free and always will be. If this post saved you some debugging time, a coffee goes a long way — no pressure, just appreciated.
☕ Buy me a coffee