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.
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.
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.
Set-Cookie: __Host-pingflow_session=opaque; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=3600Verify 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.