Secure, HttpOnly, and SameSite describe different restrictions that a supporting browser applies to cookies. The server receives the resulting name/value pairs, not a certificate that those restrictions were enforced. Keep browser behavior and server authorization separate: a cookie can be correctly delivered while the requested action is still forbidden.

Separate setting, sending, and script access

Secure restricts transmission to secure connections, normally HTTPS. Modern browser cookie rules also reject Secure cookies set from insecure contexts, with development exceptions such as localhost that must be checked in the target browser. This is more than a transmission flag. A redirect to HTTPS cannot retract a token already sent on an earlier plaintext request; deploy HTTPS and an appropriate HSTS policy as complementary protections.

HttpOnly prevents access through non-HTTP scripting APIs such as document.cookie. It does not prevent the browser from attaching that cookie to eligible requests initiated by script. Injected same-origin JavaScript can therefore still perform actions as the user even when it cannot read the token. Prevent and contain XSS independently; HttpOnly reduces one theft route rather than neutralizing the vulnerability.

SameSite adds request-context restrictions. Strict generally permits same-site requests; Lax also permits cross-site top-level navigations using safe methods. An explicit Lax cookie is not sent merely because a cross-site POST originated in a top-level page. None removes this particular restriction but requires Secure in supporting browsers. Third-party cookie blocking, storage partitioning, and the Fetch credentials mode can still prevent transmission.

A site is not an origin

For ordinary HTTPS domains, the scheme and registrable domain define the relevant schemeful site boundary. Two HTTPS sibling subdomains can be same-site while remaining different origins. Different ports also create different origins without necessarily changing the site. Consequently, Strict is not a promise to exclude every cross-origin request, and a compromised same-site sibling remains relevant to CSRF defenses.

Absent or invalid SameSite is also not a portable synonym for explicit Lax. The cookie specification permits a compatibility mode for recently created cookies with no explicit value, allowing some unsafe top-level requests. The often-mentioned two-minute window is an implementation-oriented compatibility limit, not a guarantee for every browser. Set the intended value and test supported browser versions.

When it breaks

A state-changing GET remains dangerous under Lax because a cross-site top-level safe-method navigation can carry the cookie. Make state changes require appropriate methods and server-side CSRF protection. Conversely, Strict can withhold a cookie required during a cross-site identity-provider callback. Trace the actual redirect chain and callback method; not every SSO flow fails, and a bookmark alone is not evidence of a cross-site redirect.

Use the identity library’s supported correlation and callback design rather than indiscriminately weakening the main session. Origin or Fetch Metadata checks can help when configured with explicit policies for missing headers and legitimate cross-site flows. Non-browser clients can forge these headers, so they are browser-context signals, not credentials. A client that already possesses a stolen session token needs authentication and revocation controls, not another SameSite check.

Check it quickly

Save this as cookie-flags.py and run python3 cookie-flags.py with Python 3.11 or newer. It uses the real standard-library CookieJar with synthetic response metadata, but performs no network requests. Its purpose is to expose the difference between this HTTP client’s cookie policy and a browser’s policy.

from email.message import Message
from http.cookiejar import CookieJar
from http.cookies import SimpleCookie
from urllib.request import Request


class Response:
    def info(self):
        headers = Message()
        for value in [
            "secure_sid=synthetic; Path=/; Secure; HttpOnly; SameSite=Lax",
            "strict_pref=synthetic; Path=/; SameSite=Strict",
            "insecure_none=synthetic; Path=/; SameSite=None",
        ]:
            headers.add_header("Set-Cookie", value)
        return headers


jar = CookieJar()
jar.extract_cookies(Response(), Request("https://app.example.com/login"))


def outgoing(url):
    request = Request(url)
    jar.add_cookie_header(request)
    header = request.get_header("Cookie", "")
    parsed = SimpleCookie()
    parsed.load(header)
    assert "SameSite" not in header and "HttpOnly" not in header
    return set(parsed)


assert outgoing("http://app.example.com/") == {"strict_pref", "insecure_none"}
assert outgoing("https://app.example.com/") == {
    "secure_sid", "strict_pref", "insecure_none"
}
manual = Request("http://app.example.com/",
                 headers={"Cookie": "secure_sid=synthetic"})
assert manual.get_header("Cookie") == "secure_sid=synthetic"
print("PASS: CookieJar filters Secure; it does not enforce SameSite")
print("PASS: request headers omit attributes; a manual header bypasses the jar")

The jar withholds secure_sid over HTTP and includes it over HTTPS, even though it is HttpOnly. It accepts insecure_none and sends strict_pref without modeling a page’s same-site context. Those latter results demonstrate this client’s limitations; they are not browser expectations. Constructing a Cookie header manually also bypasses the jar completely. No server response or browser outcome is established by this test.

A client holds Secure, HttpOnly, and SameSite restrictions; the server receives cookie name/value pairs. A synthetic CookieJar matrix distinguishes HTTP and HTTPS without claiming browser SameSite enforcement.
Secure, HttpOnly, and SameSite address different browser boundaries. The article’s CookieJar uses synthetic metadata with no network requests: it withholds secure_sid on HTTP, includes it on HTTPS, and does not enforce SameSite. Server authorization is separate.

For browser validation, use isolated same-site and cross-site test pages with synthetic values, checking cookie acceptance separately from outgoing requests. Cover top-level GET, POST callbacks, embedded fetches, and the application’s credentials mode. A curl request with a forged Sec-Fetch-Site header cannot establish SameSite enforcement, and an arbitrary HTTP status cannot prove that a cookie was accepted or an action authorized.

Sources