Intermediate

What Is Session Management

15 min 4 sections
1

Explanation

What Is Sessions

HTTP Sessions

HTTP is a stateless protocol. Each request is independent, and HTTP itself provides no built-in mechanism for the server to remember that two requests came from the same user.

For example:

Request 1:
POST /login
→ username + password → authentication succeeds

Request 2:
GET /dashboard
→ how does the server know this is the user who just logged in?

Without some additional mechanism, the server has no inherent connection between those two requests.

A session solves this by giving the application a way to associate multiple HTTP requests with the same ongoing interaction:

Login
  ↓
Server creates session
  ↓
Client receives session identifier
  ↓
GET /dashboard
  → session identifier included
  ↓
Server finds corresponding session
  ↓
"These requests belong to the same authenticated user"

The session can maintain state such as:

user_id        → 4521
authenticated   → true
cart_id        → 8831
checkout_step  → payment

The important distinction is:

HTTP itself
→ stateless

Application session
→ state maintained across requests

A session therefore doesn't change HTTP's underlying stateless nature. It adds an application-level mechanism for continuity on top of it.

In a typical web application, the client stores only a session identifier, commonly in a cookie:

Cookie:
session_id=abc123...

The actual session state can remain server-side:

session_id abc123...
        ↓
server-side session
        ↓
user_id = 4521
authenticated = true

That separation is important for security: the client presents an identifier, while the server determines what that identifier represents.

2

Explanation

What Is Cookies

Cookies are the dominant mechanism browsers use to carry session continuity automatically.

When the server wants to establish a session, it can send a Set-Cookie header:

Set-Cookie: session=a9f3e7c1b2d84f...; Path=/; Domain=app.example.com

The browser stores the cookie and automatically attaches it to subsequent requests that match the cookie's scope:

Cookie: session=a9f3e7c1b2d84f...

The important pieces are:

session=a9f3e7c1b2d84f...
→ cookie name + value

Path=/
→ applies to requests under /

Domain=app.example.com
→ controls which host/domain receives the cookie

The application can then use the session identifier to find the corresponding server-side session:

Browser
→ session=a9f3e7c1b2d84f

Server
→ session ID
→ server-side session
→ user_id = 4521
→ authenticated = true

The automatic attachment is what makes cookies convenient — the browser handles the mechanism without the application having to manually add the value to every request.

But that same behavior creates an important security property: ambient authority.

The browser may attach the cookie to a request regardless of whether the request was initiated by the legitimate application or triggered by another website. That's the property that makes CSRF possible.

Cookies aren't the only way to carry authentication state. APIs and applications such as SPAs or mobile clients often use an explicit authorization header:

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

The major difference is who attaches the credential:

Cookie
→ browser attaches automatically

Bearer token
→ application/client code explicitly attaches it

That difference changes the security properties.

A cross-site request can cause the browser to send matching cookies automatically:

Attacker site
     ↓
victim's browser
     ↓
request to target.example.com
     ↓
Cookie automatically attached

But the attacker generally cannot make the victim's browser automatically invent an arbitrary Authorization: Bearer ... header for that cross-site request.

So bearer tokens avoid the classic ambient-cookie CSRF mechanism — but they introduce a different concern: where the token is stored and who can read it.

For example:

localStorage
→ JavaScript can read the token
→ XSS can potentially steal it

HttpOnly cookie
→ browser sends it
→ JavaScript cannot directly read it
→ reduces token theft through XSS

This doesn't mean cookies are universally safer or bearer tokens are universally safer. They represent different security trade-offs:

Cookie
→ automatic transmission
→ CSRF becomes an important concern
→ HttpOnly can protect the credential from JavaScript access

Bearer token
→ explicit transmission
→ not automatically supplied cross-site
→ storage becomes critical
→ tokens accessible to JavaScript are attractive XSS targets

One particularly important detail is that HttpOnly doesn't prevent CSRF. It prevents JavaScript from reading the cookie, but the browser can still automatically send an HttpOnly cookie with a matching request. CSRF defenses such as SameSite cookies and CSRF tokens address that separate problem.

3

Explanation

What IS Session Identifiers

The value carried by a cookie or bearer token — the session identifier or authentication token — is what allows the server to associate a request with an authenticated client.

There are two broad ways an application can handle the state behind that identifier.

Stateful Session:

A stateful session treats the identifier as an opaque lookup key. The actual session data remains on the server:

Session ID:
a9f3e7c1b2d84f...

        ↓ lookup

Server-side session:
{
    user_id: 4521,
    authenticated: true,
    login_time: ...,
    ...
}

The identifier itself carries no meaningful user information. It's simply a pointer to the server-side record.

The important security consequence is that the server has a real session record it can modify or delete.

For example:

User logs out
        ↓
Server invalidates session record
        ↓
Old session ID
        ↓
no longer maps to a valid session
        ↓
request rejected

This is why server-side session invalidation is straightforward: the application can simply expire or remove the corresponding state.

Stateless Tokens:

A stateless approach puts the relevant claims directly inside the token rather than storing the complete session state on the server.

JWTs are the most common example:

JWT
  ↓
header + payload + signature
  ↓
claims such as:
  user_id = 4521
  role = user
  exp = ...

The server verifies the token's cryptographic signature and reads its claims without needing to retrieve a session record from a database or Redis.

Conceptually:

Request
   ↓
JWT
   ↓
verify signature
   ↓
check expiration
   ↓
read claims
   ↓
authenticate request

This has a major operational trade-off.

With a stateful session:

Invalidate session
→ delete/expire server-side record
→ old identifier stops working

With a purely stateless token:

Invalidate token
→ no server-side record to delete
→ normally remains valid until expiration

An application can add a revocation list, token version, short expiration, or another server-side mechanism to regain early invalidation but doing so introduces some state again.

The Identifier Itself

Regardless of the architecture, the credential presented by the client must be:

  • Unpredictable — attackers shouldn't be able to guess another valid identifier.

  • Sufficiently random — generated using a cryptographically secure random source where random identifiers are used.

  • Non-meaningful — it shouldn't reveal usernames, database IDs, timestamps, or other sensitive information.

    For example:

    Bad:
    session=user4521
    
    Bad:
    session=4521-1756208400
    
    Good:
    session=8f4c...long unpredictable random value...

    The difference is important because anyone who obtains a valid session credential may be able to act as the associated user.

    So the security model is essentially:

    Stateful
    client → opaque ID → server-side state
    
    Stateless
    client → signed token containing claims

    Neither model is automatically secure. The important questions are how the credential is generated, protected, transmitted, validated, expired, and invalidated.

4

Explanation

Authentication State

The most common job of a session in a web application is maintaining authentication state — remembering that this client previously completed authentication successfully and should continue to be treated as that authenticated identity.

Without a session, the server would need credentials on every request:

POST /login
→ username + password

GET /dashboard
→ username + password again

GET /orders
→ username + password again

The session removes that requirement.

The normal flow is:

1. User submits credentials
        ↓
2. Server verifies them
        ↓
3. Authentication succeeds
        ↓
4. Server creates an authenticated session
        ↓
5. Session identifier is given to the client
        ↓
6. Client sends that identifier with later requests
        ↓
7. Server retrieves/validates the session
        ↓
8. Request is treated as authenticated

With a cookie-based session:

Set-Cookie: session=a9f3e7c1b2d84f...

The browser automatically sends it on subsequent matching requests:

Cookie: session=a9f3e7c1b2d84f...

With a bearer-token architecture, the application explicitly attaches the credential:

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

The underlying idea is the same:

Successful authentication
        ↓
authenticated state established
        ↓
credential/session identifier
        ↓
subsequent requests
        ↓
server recognizes authenticated identity

The important security boundary is that authentication happens when the server establishes the state; subsequent requests rely on the continued validity of that state.

That means the session credential effectively becomes a continuation of the original authentication:

Original password
→ proves identity

Valid session
→ represents the already-authenticated identity

This is why session security matters so much. An attacker who obtains a valid session identifier may not need the user's password at all the server can treat the attacker's request as coming from the already-authenticated user.

It also explains why authentication state must be checked on every subsequent request:

Valid session?
    ↓
Yes → continue authentication/authorization processing
No  → reject or require authentication

And importantly, authentication and authorization remain separate:

Session
→ "This request belongs to user 4521."

Authorization
→ "Is user 4521 allowed to perform this action?"

A valid session proves the requester's authenticated identity; it does not automatically grant permission to every resource or operation.

You've completed Session Management

Great work — explore other topics to keep learning.