Software Dev Notes

Home › Web Development

How Cookies and Sessions Work in Web Applications

HTTP is stateless, so websites use cookies and sessions to remember users. Learn Set-Cookie, HttpOnly, Secure, SameSite and server-side sessions.

2026-10-19 · 6 min read

HTTP does not remember anything between requests. Each request arrives on its own, and the server has no built-in way to know that the same browser sent the previous one. Yet a shopping cart survives page changes and a login stays active for days. That continuity comes from cookies and sessions, two cooperating mechanisms that browsers and servers have used for decades.

This article explains how a cookie is set and sent back, what each cookie attribute does, how server-side sessions store state, and which mistakes lead to security problems. The rules described here follow the cookie specification and current browser behavior as of the date of this article.

Why HTTP needs help with state

The protocol is stateless by design. That makes it simple and easy to scale, because any server in a cluster can answer any request without knowing the history. The cost is that applications must add memory when they need it.

Developers have three broad options. The server can store all state and give the client a reference to it. The client can store the state and send it with every request. Or the two can share the work, with a small reference stored on the client and the real data kept on the server. Cookies and sessions implement the third option, and it is the most common design for logged-in websites.

How a cookie is set and sent back

A server sets a cookie by including a Set-Cookie header in a response. The header contains a name, a value and optional attributes, separated by semicolons. The browser stores the cookie and attaches it as a Cookie header to later requests that match the cookie's domain and path.

For example, a server might send a session identifier such as a long random string. Every later request from that browser carries the same string, and the server uses it to look up the matching record. The browser does not understand the cookie's meaning. It only stores and returns it according to the rules.

Cookies are limited in size. RFC 6265 says browsers should support at least 4096 bytes per cookie, counting the name, value and attributes together. Large data belongs on the server, with only an identifier in the cookie.

The attributes that matter

Each attribute changes how the browser stores or sends the cookie. Setting them correctly is one of the simplest ways to make a site safer.

Attribute What it does Typical setting
Domain Sets which hosts receive the cookie Omit it to limit the cookie to the exact host
Path Limits the cookie to a URL prefix Often "/" for site-wide sessions
Max-Age or Expires Sets how long the browser keeps the cookie A short lifetime for sensitive sessions
Secure Sends the cookie only over HTTPS Always on for session cookies
HttpOnly Hides the cookie from JavaScript Always on for session cookies
SameSite Controls sending on cross-site requests Lax or Strict for most sessions

Without Max-Age or Expires, a cookie is a session cookie and disappears when the browser closes. With either attribute it persists until that time. Omitting Domain is safer than setting it, because a broad domain value shares the cookie with every subdomain.

What HttpOnly and Secure protect against

HttpOnly stops page scripts from reading the cookie through document.cookie. If an attacker manages to inject a script through a cross-site scripting bug, the script cannot copy a session identifier that has this flag. The attacker can still act inside the victim's browser while the page is open, so HttpOnly reduces the damage without removing the need to fix the bug.

Secure makes the browser send the cookie only over HTTPS connections. Without it, a cookie set over a plain HTTP connection could be read by anyone on the network path. Browsers also refuse to set a Secure cookie from a plain HTTP page, so setting it is the expected default for session cookies.

SameSite and cross-site requests

SameSite addresses a different threat, cross-site request forgery, in which a malicious page causes the victim's browser to submit a request to another site. The browser normally attaches that site's cookies to the request, so the target server may treat the request as authentic.

SameSite tells the browser when to include the cookie. Strict sends it only for requests that start within the same site. Lax sends it for same-site requests and for top-level navigations such as following a link, but not for most cross-site subrequests such as form posts or embedded images. None sends it on all requests, and it must be paired with Secure.

Chromium-based browsers such as Chrome and Edge now apply Lax as the default when a cookie omits the attribute. That default protects many sites without changes, but applications that rely on cross-site embedding must set None explicitly and accept the extra exposure.

Server-side sessions

A session is the server-side record that the cookie points to. A typical flow works like this. The user submits a login form. The server checks the password against a stored hash. It then creates a random session identifier, stores a record with the user ID, creation time and expiry in a database or cache, and sends the identifier in a Set-Cookie header.

On each later request, the server reads the cookie, finds the record and loads the user data. If the record is missing or expired, the server treats the user as logged out. Logging out deletes the record, so a stolen identifier stops working right away. Storing sessions on the server makes that revocation possible, which is harder when all state lives inside a signed token on the client.

The identifier must be long and random. Guessing a value with enough entropy is not practical, so the security depends on the generator, not on the length of the cookie name.

Common mistakes

Several errors appear repeatedly in real applications.

Some sites keep the user ID in a plain cookie and trust it on later requests. Anyone who edits the cookie can then impersonate another user. The fix is to keep identity on the server or to sign the value cryptographically.

Other sites never change the session identifier after login. An attacker who plants a known identifier in the victim's browser can then use it after the victim signs in. Issuing a new identifier at login time closes that gap.

Developers also sometimes store secrets in cookies that JavaScript needs to read. If a value must be read by scripts, it should not be a session secret, and the sensitive part should stay in an HttpOnly cookie.

Cookies compared with browser storage

Web storage APIs such as localStorage keep data in the browser, but they are not sent automatically with requests and they are readable by any script on the page. That makes them useful for preferences and cached data, and a poor place for session secrets. Cookies with HttpOnly are the right tool for authentication state, because the browser handles them without exposing them to page code.

Key takeaways

HTTP is stateless, so applications rebuild continuity with cookies and sessions. A cookie carries a small value that the browser returns on later requests, and a server-side session record holds the real data that the cookie identifies.

Secure session handling depends on a few settings: Secure, HttpOnly and a suitable SameSite value, plus a new identifier at login and deletion on logout. Getting those details right prevents most common cookie-based attacks.

More in Web Development

Web

How HTTP Request and Response Work, Step by Step

HTTP is the request and response protocol behind the web. This guide walks through methods, headers, status codes and what happens on each request.

5 min read