DEV_NET_CORE
GET_STARTED
ReactProduction data access, API clients, and frontend auth

Secure cookie flags: `HttpOnly`, `Secure`, `SameSite`, path, domain, and expiration

Overview

Secure cookie flags are attributes that control how browsers store and send cookies. In React applications, cookies are often used for server-managed sessions, refresh tokens, CSRF tokens, preferences, or identity provider flows. The most important attributes for interviews are HttpOnly, Secure, SameSite, Path, Domain, Expires, and Max-Age.

This topic matters because cookie behavior is deceptively simple. A single missing flag can expose a session to JavaScript theft, allow cross-site request forgery, send credentials to too many subdomains, or keep a user logged in longer than intended.

React does not make cookies secure by itself. Cookie security is mainly controlled by the server's Set-Cookie header, browser behavior, HTTPS, CORS, CSRF protections, and the backend's authorization checks. The frontend must understand the consequences because API clients, route guards, refresh flows, and unauthorized UX all depend on the authentication model.

For interviews, this topic tests whether a candidate can explain browser security controls precisely and connect them to practical app behavior.

Core Concepts

A cookie is usually set by the server with a Set-Cookie response header.

Example:

Code
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600

After the browser stores the cookie, it sends the cookie on future requests that match the cookie's domain, path, security, and same-site rules.

Important cookie facts:

  • Cookies are small compared with other browser storage mechanisms.
  • Cookies are sent automatically with matching requests.
  • A server can set cookies that JavaScript cannot read.
  • Cookies are scoped by domain and path.
  • Cookies can expire at browser close or at a configured time.
  • Cookies are not a complete security solution without server-side validation.

HttpOnly

HttpOnly tells the browser not to expose the cookie through JavaScript APIs such as document.cookie.

Example:

Code
Set-Cookie: refreshToken=abc123; HttpOnly; Secure; SameSite=Strict; Path=/auth/refresh

Why it matters:

  • Reduces direct cookie theft from XSS.
  • Protects session IDs and refresh tokens from ordinary JavaScript access.
  • Forces auth logic to rely on server validation or session endpoints instead of reading the token in React.

What it does not do:

  • It does not stop the browser from sending the cookie with matching requests.
  • It does not prevent CSRF by itself.
  • It does not prevent XSS from performing actions as the user while the cookie is present.
  • It does not remove the need for output encoding and CSP.

For session or refresh cookies, HttpOnly is usually expected.

Secure

Secure tells the browser to send the cookie only over secure HTTPS requests.

Example:

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

Why it matters:

  • Reduces exposure over plaintext HTTP.
  • Should be used for authentication cookies.
  • Is required for SameSite=None.

Important nuance:

  • Secure protects transmission, not JavaScript access.
  • Secure does not replace HttpOnly.
  • Local development may need HTTPS or special local handling.

Production authentication cookies should use Secure.

SameSite

SameSite controls whether a cookie is sent with cross-site requests.

Common values:

  • Strict: send the cookie only for same-site requests.
  • Lax: send the cookie for same-site requests and some top-level safe navigations.
  • None: send the cookie in cross-site contexts; must be paired with Secure.

Example:

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

Choosing a value:

  • Strict is strongest but can break sign-in redirects, links from email, or identity provider flows.
  • Lax is a practical default for many session cookies.
  • None is needed for true cross-site embedding or some third-party scenarios, but it increases CSRF exposure and requires careful controls.

SameSite helps reduce CSRF risk, but it should not be the only defense for sensitive unsafe operations.

Path

Path controls which URL paths receive the cookie.

Example:

Code
Set-Cookie: refreshToken=abc123; HttpOnly; Secure; SameSite=Strict; Path=/auth/refresh

If Path=/, the cookie is sent to the whole site. If Path=/auth/refresh, it is only sent to requests under that path.

Useful patterns:

  • Session cookie with Path=/ when the whole app needs it.
  • Refresh token cookie with a narrow refresh endpoint path.
  • CSRF cookie with a path that matches the API surface that needs it.

Limits:

  • Path is not a strong security boundary against malicious code on the same origin.
  • It mainly controls request matching.
  • A broad Path=/ increases where the cookie is sent.

Use the narrowest path that still supports the app's flow.

Domain

Domain controls which hosts receive the cookie. If omitted, the cookie is host-only and applies only to the exact host that set it.

Example host-only cookie:

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

Example broader domain cookie:

Code
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax; Domain=example.com; Path=/

Trade-off:

  • Omitting Domain is usually safer because the cookie is limited to the exact host.
  • Setting Domain=example.com allows subdomains to receive the cookie.
  • If any subdomain is less trusted, broad domain cookies increase risk.

For sensitive auth cookies, prefer host-only cookies unless there is a clear cross-subdomain requirement.

Expiration: Session Cookies, Expires, and Max-Age

Cookie lifetime is controlled by Expires or Max-Age.

Examples:

Code
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax; Path=/
Code
Set-Cookie: remember=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=2592000

If a cookie has no explicit expiration, it is a session cookie and is typically removed when the browser session ends. Browser session restore features can affect user expectations, so do not rely on this alone for critical security.

Max-Age sets lifetime in seconds. Expires sets an absolute date. When both are present, modern behavior gives Max-Age precedence.

For authentication:

  • Use short lifetimes for high-risk credentials.
  • Match cookie lifetime to server session lifetime.
  • Expire cookies on logout.
  • Rotate refresh tokens where appropriate.

To delete a cookie, the server must set the same cookie name with matching Path and Domain attributes and an expiration in the past or Max-Age=0.

Example:

Code
Set-Cookie: session=; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=0

Important:

  • JavaScript cannot delete an HttpOnly cookie.
  • The server must expire it.
  • Path and domain must match the original cookie.
  • Server-side session state should also be invalidated.

Logout should not only remove the browser cookie. It should also invalidate the session or refresh token server-side.

Cookie name prefixes can add browser-enforced constraints.

Common prefixes:

  • __Secure-: cookie must be set with Secure from a secure origin.
  • __Host-: cookie must be set with Secure, must not include Domain, and must use Path=/.

Example:

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

The __Host- prefix is useful for sensitive host-bound cookies because it prevents broad domain scoping.

When React uses cookie-based auth, the frontend often does not read the credential directly. Instead, it asks the server for session state.

Example:

Code
async function loadCurrentUser() {
  const response = await fetch("/api/me", {
    credentials: "include",
  });

  if (response.status === 401) {
    return null;
  }

  if (!response.ok) {
    throw new Error("Failed to load session");
  }

  return response.json() as Promise<User>;
}

The frontend sees whether the user is authenticated based on server responses, not by reading the cookie.

For cross-origin APIs, credentialed requests also require correct CORS configuration from the server.

SameSite and OAuth Redirects

Authentication flows often involve redirects between an app and an identity provider. SameSite=Strict can break some redirect-based flows because the browser may not send the cookie when returning from another site.

Common approach:

  • Use SameSite=Lax for main session cookies when top-level sign-in redirects are expected.
  • Use SameSite=None; Secure only when cross-site sending is required.
  • Use state and nonce parameters for OAuth/OIDC flows.
  • Keep unsafe state-changing actions protected by CSRF controls.

The strongest cookie setting is not always the setting that works for the product. The correct setting balances security and the required navigation flow.

Cookie flags reduce CSRF risk but do not eliminate every scenario.

Defense layers:

  • SameSite=Lax or Strict where compatible.
  • CSRF tokens for unsafe actions.
  • Origin or Referer validation.
  • No state-changing behavior on GET.
  • CORS allow-listing for credentialed APIs.

Example double-submit style shape:

Code
Set-Cookie: csrf=token-value; Secure; SameSite=Lax; Path=/

The JavaScript-readable CSRF cookie is different from an HttpOnly session cookie. It does not authenticate the user by itself. It is used to prove that the request came from a page that could read the CSRF value.

Local Development

Secure cookie behavior can be awkward locally.

Common approaches:

  • Run local development over HTTPS.
  • Use localhost-specific exceptions where the platform supports them.
  • Keep production flags in production configs.
  • Avoid weakening production behavior for local convenience.

Do not ship development cookie settings such as missing Secure, broad Domain, or SameSite=None without a real need.

Common Mistakes

Common mistakes include:

  • Setting session cookies without HttpOnly.
  • Setting auth cookies without Secure in production.
  • Using SameSite=None without understanding cross-site risk.
  • Setting a broad Domain for sensitive cookies.
  • Using Path=/ for refresh tokens that only need one endpoint.
  • Forgetting that JavaScript cannot delete HttpOnly cookies.
  • Clearing the browser cookie but not invalidating the server session.
  • Relying only on SameSite for all CSRF protection.
  • Assuming Path is a strong security boundary.
  • Logging Set-Cookie headers or cookie values.

Best Practices

Best practices include:

  • Use HttpOnly for session and refresh cookies.
  • Use Secure for production auth cookies.
  • Prefer SameSite=Lax or Strict unless cross-site behavior is required.
  • Use SameSite=None; Secure only with a clear need.
  • Prefer host-only cookies by omitting Domain.
  • Use narrow Path values when possible.
  • Align cookie expiration with server session expiration.
  • Expire cookies and invalidate server sessions on logout.
  • Consider __Host- for sensitive host-bound cookies.
  • Add CSRF protection for unsafe cookie-authenticated requests.
  • Keep frontend auth state derived from server validation.

Interview Practice

PreviousRTK Query custom base queries, including Axios-based baseQuery patternsNext Up`watch` vs `useWatch`, form render isolation, and large-form performance