All resources
Identity10 min read

Secure session cookies for modern web applications

Set cookie attributes, rotation, expiration, and CSRF defenses so browser sessions remain convenient without becoming ambient authority.

A practical PingFlow guide for developers working at the boundary between systems.

At a glance

Key takeaways

  • A session cookie is an authority token
  • Set Secure, HttpOnly, and SameSite deliberately
  • Rotate after authentication and privilege changes
In this guide

Set Secure, HttpOnly, and SameSite deliberately

Secure prevents the browser from sending the cookie over plain HTTP. HttpOnly prevents ordinary page scripts from reading it, reducing direct theft through XSS. SameSite controls whether the browser attaches it to cross-site requests. Lax is a useful default for many navigation flows, Strict is stronger but can affect external sign-in and deep links, and None requires Secure and allows cross-site sending. Choose from the application's redirects and form behavior, not a copy-pasted snippet.

Set a narrow Path and avoid a broad Domain unless subdomain sharing is required. A cookie scoped to .example.com can be sent to a less-trusted subdomain that has a different deployment or takeover risk. Use a distinct name for production and local environments. Inspect the actual Set-Cookie response through the CDN because a proxy or framework middleware can change attributes.

Rotate after authentication and privilege changes

Session fixation occurs when an attacker can make a victim use a session identifier known to the attacker and then benefit when the victim logs in. Rotate the session identifier after login, MFA completion, password reset, and privilege elevation. Keep the account and device state while replacing the bearer token. Invalidate the old identifier immediately or after a tightly bounded transition when a flow requires it.

Track a session version or security timestamp on the account so password changes, account suspension, and security incidents can invalidate all sessions. Provide per-device session management where the product needs it. A session that lives forever is difficult to revoke and increases the impact of a stolen cookie. Use an absolute lifetime plus an idle timeout, and refresh only when the session is active and the risk policy allows it.

Defend state-changing requests against CSRF

SameSite reduces many cross-site requests but does not eliminate every CSRF path, especially when integrations or legacy browser behavior require cross-site cookies. Protect state-changing requests with a server-validated CSRF token, an origin or referer check where appropriate, or a same-origin request design that does not rely on ambient cookies. A token must be tied to the session and compared safely; a hidden field that is merely echoed is not protection.

Keep GET, HEAD, and OPTIONS free of state changes. A link or image should not delete data or change an email address. If a product must support cross-origin API calls, separate the credential model and use explicit authorization headers with CORS rules rather than making every browser request carry an ambient session.

Handle expiration and logout everywhere

A logout endpoint should revoke the server session and send an expired cookie with matching name, path, and domain attributes. Clearing a cookie with a different path creates a second cookie that remains active. When an account is disabled or a password changes, reject the session server-side even if the browser still presents it. Do not rely on a client redirect as proof that logout succeeded.

Return a consistent unauthenticated response and avoid exposing whether a session existed. For API requests, the client can clear local state and navigate to login. For HTML requests, preserve a safe return path without reflecting arbitrary URLs. Audit session creation, rotation, revocation, and unusual geographic or device changes with privacy-conscious identifiers.

Observe cookies without logging them

Logs should record session ID hashes or internal session references, never raw cookie headers. Track authentication success, failure, rotation, revocation, idle expiration, absolute expiration, and CSRF rejection categories. Do not put session values into tracing baggage, URLs, exception messages, or client analytics. A support tool can show session age, device label, and last activity without revealing the credential.

Monitor unexpected increases in session creation, failed CSRF checks, and sessions active after a global revocation. Correlate events with a request ID and account-safe identifier. The goal is to detect abuse and explain user reports without creating a second store of credentials.

Test browsers and hostile requests

Test HTTPS and HTTP, cross-site forms, redirects, subdomains, login rotation, password reset, MFA elevation, logout from multiple tabs, cookie path changes, expired sessions, and a stolen-cookie simulation. Verify that XSS cannot read HttpOnly cookies and that CSRF cannot perform a state change. Test the app behind the production proxy because secure and host-only behavior can differ from localhost.

Secure sessions are an end-to-end contract: scoped cookie attributes, server-side revocation, rotation at trust changes, CSRF protection, bounded lifetime, and safe diagnostics. A single Secure flag is not a session design. Make each property explicit so a framework upgrade or new subdomain cannot quietly widen authority.

Pair cookies with server-side revocation

Cookie flags reduce browser exposure, but a session also needs a server-side lifetime, rotation policy, and revocation path. Rotate identifiers after login and privilege changes, reject reused refresh credentials, and invalidate sessions after a confirmed account event. Test subdomain boundaries, cross-site navigation, logout in multiple tabs, and a stolen old cookie. The browser should hold an opaque handle while the server decides whether that handle still represents an active session.

Implementation example

Set an opaque, high-entropy session identifier with the narrowest Domain and Path, Secure, HttpOnly, and an intentional SameSite policy. Rotate the identifier after login and privilege changes, store server-side expiry and revocation state, and keep refresh credentials separate from short-lived access state.

http
Set-Cookie: __Host-pingflow_session=opaque; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=3600

Verify and troubleshoot

Test login, logout in multiple tabs, cross-site navigation, subdomain boundaries, proxy termination, refresh rotation, expired sessions, and a stolen old cookie. Inspect browser cookie attributes and server revocation state together. Confirm that an authenticated request cannot be created from a cookie that was issued before a privilege change.

Operations and recovery

Monitor session creation, refresh reuse, revocation events, unusual geographic changes, and authentication failures without logging cookie values. Maintain an incident checklist for key rotation, session invalidation, cookie expiry, and user notification. If an origin or CDN changes, review Domain, Secure, SameSite, proxy, and callback behavior before release.

References and further reading

Use RFC 6265bis, OWASP Session Management Cheat Sheet, and the browser's cookie attribute documentation. Keep authentication, authorization, CSRF defense, and session storage as separate decisions.

Keep exploring