Cookies are often a small implementation detail in an authentication system, but their configuration can have a significant impact on security.
In session-based authentication, for example, a cookie usually stores a session identifier such as a session_id.
That identifier is effectively a credential. If an attacker obtains a valid session cookie, they may be able to impersonate the user without ever knowing their password.
That’s why configuring authentication cookies correctly matters.
HttpOnly
The HttpOnly attribute prevents JavaScript running in the browser from accessing the cookie through APIs such as document.cookie.
Set-Cookie: session_id=abc123; HttpOnly
This is particularly important when thinking about XSS attacks.
Without HttpOnly, malicious JavaScript running on the page could read the session identifier and send it to an attacker.
With HttpOnly, JavaScript cannot directly access the cookie.
It doesn’t prevent XSS itself, but it makes stealing the authentication cookie through JavaScript considerably harder.
Secure
The Secure attribute tells the browser to send the cookie only over HTTPS connections.
Set-Cookie: session_id=abc123; HttpOnly; Secure
For authentication cookies, this should normally be enabled in production.
Without it, there is a risk of the cookie being transmitted over an unencrypted HTTP connection if such a connection is possible.
HTTPS protects the communication channel, while Secure ensures that the browser doesn’t send that cookie over regular HTTP.
SameSite
SameSite controls when the browser sends a cookie in cross-site requests.
The three main values are Strict, Lax, and None.
SameSite=Strict
Set-Cookie: session_id=abc123; SameSite=Strict
With Strict, the browser generally doesn’t send the cookie in cross-site contexts.
This provides strong protection against many CSRF scenarios, but it can also affect legitimate flows that begin on another site.
For example, a user following an external link into an authenticated application may initially arrive without the session cookie being included.
SameSite=Lax
Set-Cookie: session_id=abc123; SameSite=Lax
Lax provides a balance between security and usability and is the default behavior in modern browsers when SameSite is not explicitly specified.
Cookies can still be included in certain top-level cross-site navigations, particularly safe HTTP methods such as GET.
This is also one of the reasons why sensitive operations should never be performed through GET requests.
An endpoint such as:
GET /account/delete
would be a bad design regardless of cookie configuration.
Operations that change application state should use appropriate HTTP methods and should not rely exclusively on SameSite as their CSRF defense.
SameSite=None
Set-Cookie: session_id=abc123; SameSite=None; Secure
None allows the cookie to be sent in cross-site contexts.
Browsers require cookies using SameSite=None to also use Secure.
This configuration may be necessary for applications that intentionally operate across different sites, but it also means that explicit CSRF protections may be required depending on the authentication flow and architecture.
Putting the attributes together
A session cookie might look something like this:
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=604800
Each attribute solves a different problem.
HttpOnly limits JavaScript access to the cookie.
Secure restricts transmission to HTTPS.
SameSite controls how the cookie behaves in cross-site requests.
Max-Age defines how long the cookie should remain valid in the browser.
None of these attributes should be treated as a complete security mechanism on its own. They work together as part of the authentication strategy.
Expiration and session lifecycle
Cookie security isn’t only about HttpOnly, Secure, and SameSite.
The lifetime of the session also matters.
Authentication systems should consider:
- An appropriate expiration time
- Session invalidation during logout
- Session revocation
- Token or session rotation when appropriate
- Invalidation after security-sensitive events
A session that remains valid indefinitely increases the impact of a stolen credential.
The appropriate lifetime depends on the application and its security requirements.
Common mistakes
Some common problems when implementing cookie-based authentication include:
- Not using
HttpOnlyfor authentication cookies - Forgetting
Securein production - Using
SameSite=Nonewithout actually needing cross-site cookies - Relying exclusively on
SameSitefor CSRF protection - Using excessively long session expiration times
- Failing to invalidate sessions during logout
- Storing sensitive authentication tokens in
localStoragewithout considering the security trade-offs
The last point is particularly important.
Unlike an HttpOnly cookie, values stored in localStorage are directly accessible to JavaScript running on the page. This makes the consequences of an XSS vulnerability different and should be considered when deciding where authentication credentials should live.
What about JWT?
Using JWT doesn’t make cookie configuration irrelevant.
A JWT defines a token format. It doesn’t determine where that token needs to be stored.
If a JWT is stored inside a cookie:
Set-Cookie: access_token=eyJ...; HttpOnly; Secure; SameSite=Lax
then the same cookie security considerations still apply.
The difference is simply what the cookie contains.
In a traditional session-based system, it might contain:
session_id
With JWT-based authentication, it might contain:
access_token
In both cases, the value represents an authentication credential and needs to be protected accordingly.
Final thoughts
Authentication security isn’t only about validating a password, generating a token, or creating a session.
A significant part of it comes from smaller decisions around how credentials are stored, transmitted, expired, and revoked.
Cookie configuration is one of those decisions.
A login flow can be correctly implemented while the authentication system remains unnecessarily exposed because of a poorly configured cookie.
Understanding attributes such as HttpOnly, Secure, and SameSite is therefore an important part of designing authentication systems for the web.
