Insights into Company
← Backend Concepts in Depth topics

Sessions & Cookies

How stateless HTTP remembers a logged-in user: cookies on the browser, sessions on the server, the security flags that protect them, session storage when you have many servers, and how Spring Boot and React handle the same problem.

Running examples: guest cart that survives login, banking idle timeout, remember-me

1. Cookies and sessions explained

HTTP is stateless: the server forgets you after each response. A cookie is a small name=value pair the server asks the browser to store (Set-Cookie header); the browser sends it back on every later request to that site (Cookie header).

A session keeps the data on the server and puts only a random id in the cookie. The browser holds laravel_session=Abc; the server holds Abc => {user_id: 42, cart_id: 9}. Users cannot read or edit server-side data, and large data never travels with each request.

What travels over the wire

POST /login HTTP/1.1                      (credentials checked)

HTTP/1.1 302 Found
Set-Cookie: laravel_session=eyJpdiI6...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=7200

GET /orders HTTP/1.1
Cookie: laravel_session=eyJpdiI6...       (browser sends it automatically)
Cookie security flags
FlagEffectProtects against
SecureSent only over HTTPSTheft on public Wi-Fi
HttpOnlyJavaScript cannot read itXSS stealing the session
SameSite=Lax/StrictNot sent on cross-site POSTs (Strict: no cross-site at all)CSRF
Max-Age / ExpiresWhen the browser deletes itSessions living forever on shared PCs
Domain / PathWhich hosts and paths receive itLeaking to other subdomains

2. Sessions in Laravel

Guest cart merged at login, then session id regenerated

// Adding to cart as a guest
$cart = session('cart', []);
$cart[$product->id] = ($cart[$product->id] ?? 0) + 1;
session(['cart' => $cart]);

// After successful login
public function authenticated(Request $request, User $user)
{
    foreach (session()->pull('cart', []) as $productId => $qty) {
        $user->cartItems()->updateOrCreate(['product_id' => $productId], ['quantity' => DB::raw("quantity + {$qty}")]);
    }
    $request->session()->regenerate();      // new id: blocks session fixation attacks
}

// Logout
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();     // new CSRF token

Banking settings in config/session.php (via .env)

SESSION_DRIVER=redis          # shared by every app server
SESSION_LIFETIME=10           # minutes idle before logout
SESSION_EXPIRE_ON_CLOSE=true
SESSION_SECURE_COOKIE=true
SESSION_ENCRYPT=true

Flash data (session()->flash("status", "Order placed")) lives for exactly one more request, which is how "saved successfully" messages survive a redirect. Remember-me uses a separate long-lived cookie holding a token that is checked against users.remember_token; turn it off for banking.

3. Sessions with many servers

With the default file driver each server keeps its own session files, so a load balancer that sends the next request to another server logs the user out. Fix it with a shared store (Redis, database, Memcached) or with sticky sessions. Shared storage is preferred because sticky sessions break when a server is removed during a deployment.

Session drivers
DriverSpeedMulti-serverNotes
fileGoodNoDefault; fine for one server or shared hosting
cookieGoodYesWhole session in an encrypted cookie, 4 KB max, cannot be revoked server-side
databaseOKYesEasy to list and delete a user's sessions ("log out all devices")
redisExcellentYesUsual production choice

Spring Boot: the same with Spring Session + Redis

// build.gradle: implementation 'org.springframework.session:spring-session-data-redis'
// application.yml
// spring.session.store-type: redis
// server.servlet.session.timeout: 10m
// server.servlet.session.cookie: { http-only: true, secure: true, same-site: strict }

@GetMapping("/cart")
public Cart cart(HttpSession session) {
    return (Cart) Optional.ofNullable(session.getAttribute("cart")).orElseGet(Cart::new);
}

4. React SPA: cookies vs storage

A React app on the same site as the Laravel API can simply use the session cookie (Sanctum SPA mode): call /sanctum/csrf-cookie once, then log in, and every fetch with credentials: "include" is authenticated. This is safer than tokens in localStorage because the cookie is HttpOnly.

Sanctum SPA login from React

await fetch('/sanctum/csrf-cookie', { credentials: 'include' });   // sets XSRF-TOKEN cookie
await fetch('/login', {
  method: 'POST',
  credentials: 'include',
  headers: { 'Content-Type': 'application/json', 'X-XSRF-TOKEN': decodeURIComponent(getCookie('XSRF-TOKEN')) },
  body: JSON.stringify({ email, password }),
});
const me = await (await fetch('/api/user', { credentials: 'include' })).json();
Where to keep client state
DataWhere
Session / authHttpOnly cookie set by the server
Theme, languagelocalStorage
Form draftsessionStorage or React state
Card number, passwordNowhere on the client; send once over HTTPS

5. Interview questions

Session vs cookie?

A cookie is stored in the browser; a session is stored on the server and identified by a cookie. Cookies can be read or edited by the user unless encrypted/signed; sessions cannot.

What is session fixation?

An attacker gets the victim to use a session id the attacker knows, then waits for the login. Regenerating the id at login defeats it.

Why is the user logged out randomly behind a load balancer?

File sessions on separate servers; move to Redis or database sessions.

How do you implement "log out from all devices"?

Use database/Redis sessions with user_id and delete them, delete all API tokens, and rotate remember_token.