Skip to content
Cookies and Sessions: Web Authentication Fundamentals

Cookies and Sessions: Web Authentication Fundamentals

DodaTech Updated Jun 20, 2026 7 min read

Cookies and sessions are the foundation of web authentication — they let websites remember who you are across HTTP requests in a stateless protocol.

What You’ll Learn

By the end of this tutorial, you’ll understand how cookies work (Set-Cookie, domain/path/secure/HttpOnly/SameSite attributes), server-side session management, session IDs, token-based authentication vs sessions, and CSRF protection. Prerequisites: HTTP Protocol basics and Python fundamentals.

Why It Matters

Without cookies and sessions, every page load would require a login. Every “Remember me” checkbox, every shopping cart, every authenticated API call — all built on cookies and sessions.

Real-World Use

When you log into Gmail, Google sets a session cookie. Every subsequent request includes this cookie, telling the server “this request is from the logged-in user” — without re-entering your password.

Cookie Flow


sequenceDiagram
  participant Browser
  participant Server
  
  Browser->>Server: POST /login (username + password)
  Server->>Server: Verify credentials
  Server-->>Browser: 200 OK + Set-Cookie: session_id=abc123; HttpOnly; Secure
  Note over Browser: Stores cookie
  Browser->>Server: GET /dashboard (Cookie: session_id=abc123)
  Server->>Server: Look up session
  Server-->>Browser: 200 OK (Dashboard HTML)

Prerequisites: HTTP Protocol fundamentals, Web Security basics, and Python.

How Cookies Work

HTTP is stateless — the server doesn’t remember who made each request. Cookies solve this by letting the server store small pieces of data (max 4KB) in the browser.

# Simple cookie setting with Python http.server
from http.server import HTTPServer, BaseHTTPRequestHandler
from datetime import datetime, timedelta
import uuid

class CookieHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/set-cookie':
            # Set a session cookie
            session_id = str(uuid.uuid4())
            self.send_response(200)
            self.send_header('Set-Cookie',
                f'session_id={session_id}; HttpOnly; Path=/; Max-Age=3600')
            self.send_header('Content-Type', 'text/plain')
            self.end_headers()
            self.wfile.write(b'Cookie set!')

        elif self.path == '/check-cookie':
            cookies = self.headers.get('Cookie', 'No cookies')
            self.send_response(200)
            self.send_header('Content-Type', 'text/plain')
            self.end_headers()
            self.wfile.write(f'Received cookies: {cookies}'.encode())

# Server would run on localhost:8000
print("Cookie server ready on port 8000")

Cookie Attributes

Each cookie can have attributes that control its behavior:

import uuid

def create_session_cookie():
    session_id = str(uuid.uuid4())
    cookie_parts = [
        f'session_id={session_id}',
        'Domain=.example.com',       # Available to all subdomains
        'Path=/',                     # Available to entire site
        'Max-Age=86400',              # Expires in 1 day
        'HttpOnly',                   # Not accessible via JavaScript
        'Secure',                     # Only sent over HTTPS
        'SameSite=Lax',               # CSRF protection
    ]
    return '; '.join(cookie_parts)

print("Cookie string:")
print(create_session_cookie())

Expected output:

Cookie string:
session_id=550e8400-e29b-41d4-a716-446655440000; Domain=.example.com; Path=/; Max-Age=86400; HttpOnly; Secure; SameSite=Lax

Important Attributes Explained

AttributePurposeExample
HttpOnlyPrevents JavaScript access — stops XSS attacks from stealing cookiesHttpOnly
SecureOnly sends cookie over HTTPS — prevents network sniffingSecure
SameSiteControls when cookies are sent cross-site — prevents CSRFSameSite=Lax
DomainWhich domains can receive the cookieDomain=.example.com
PathWhich URL path the cookie applies toPath=/
Max-Age / ExpiresCookie lifetimeMax-Age=3600

Server-Side Sessions

Server-side sessions store user data on the server, with only a session ID in the cookie:

import uuid
import json
from datetime import datetime

class SessionStore:
    def __init__(self):
        self.sessions = {}

    def create_session(self, user_data):
        session_id = str(uuid.uuid4())
        self.sessions[session_id] = {
            'user': user_data,
            'created_at': datetime.now().isoformat(),
            'last_access': datetime.now().isoformat(),
        }
        return session_id

    def get_session(self, session_id):
        session = self.sessions.get(session_id)
        if session:
            session['last_access'] = datetime.now().isoformat()
        return session

    def destroy_session(self, session_id):
        return self.sessions.pop(session_id, None)

# Usage
store = SessionStore()

# Login
sid = store.create_session({'user_id': 42, 'username': 'alice'})
print(f"Session cookie: session_id={sid}")

# Subsequent request
session = store.get_session(sid)
print(f"Session data: {session['user']}")

Expected output:

Session cookie: session_id=550e8400-e29b-41d4-a716-446655440000
Session data: {'user_id': 42, 'username': 'alice'}

Token-Based Auth vs Sessions

AspectServer SessionsToken-Based (JWT)
StorageServer-side (memory/DB/Redis)Client-side (browser stores token)
ScalabilityNeed shared session store across serversStateless — any server can verify the token
RevocationImmediate — delete session from storeHard — must maintain a blocklist
PayloadSession ID only (data on server)User data encoded in the token
ImplementationSimpler for traditional web appsBetter for APIs and microservices
ExpiryServer-controlledToken-embedded (can’t change until expiry)
# JWT example (conceptual)
import jwt
import datetime

SECRET_KEY = 'your-secret-key'

def create_jwt(user_id, username):
    payload = {
        'user_id': user_id,
        'username': username,
        'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1),
        'iat': datetime.datetime.utcnow()
    }
    token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
    return token

def verify_jwt(token):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
        return payload
    except jwt.ExpiredSignatureError:
        return None
    except jwt.InvalidTokenError:
        return None

# Create and verify a token
token = create_jwt(42, 'alice')
print(f"JWT Token: {token[:50]}...")
payload = verify_jwt(token)
print(f"Verified: user_id={payload['user_id']}, username={payload['username']}")

Expected output:

JWT Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Verified: user_id=42, username=alice

CSRF Protection

Cross-Site Request Forgery (CSRF) tricks authenticated users into performing unwanted actions. SameSite cookies and CSRF tokens prevent this.

import secrets
from datetime import datetime

class CSRFProtection:
    def __init__(self):
        self.tokens = {}

    def generate_token(self, session_id):
        token = secrets.token_hex(32)
        self.tokens[session_id] = {
            'token': token,
            'created_at': datetime.now().isoformat()
        }
        return token

    def validate_token(self, session_id, token):
        stored = self.tokens.get(session_id)
        if stored and stored['token'] == token:
            del self.tokens[session_id]
            return True
        return False

csrf = CSRFProtection()
session_id = 'abc123'

# Generate token (put in form)
form_token = csrf.generate_token(session_id)
print(f"CSRF token (in form): {form_token[:16]}...")

# Validate on form submission
is_valid = csrf.validate_token(session_id, form_token)
print(f"Token valid: {is_valid}")

Expected output:

CSRF token (in form): a1b2c3d4e5f6g7h8...
Token valid: True

Common Cookies & Sessions Errors

1. Not Using HttpOnly

Cookies accessible via JavaScript (document.cookie) can be stolen by XSS attacks. Always set HttpOnly for session cookies.

2. Missing Secure Flag on HTTPS Sites

Session cookies sent over unencrypted HTTP can be intercepted by anyone on the same network. Add Secure to all session cookies.

3. Wrong SameSite Configuration

SameSite=None requires Secure. SameSite=Lax prevents most CSRF but allows top-level navigation. Choose based on your needs.

4. Session Fixation

An attacker sets a user’s session ID to a known value. Always regenerate the session ID after login.

5. Not Setting Domain Correctly

Setting Domain=example.com makes the cookie available to all subdomains. A compromised subdomain can steal cookies intended for the main domain.

Practice Questions

1. Why do we need cookies in HTTP? HTTP is stateless — each request is independent. Cookies let servers maintain state across requests (e.g., “user is logged in”).

2. What does the HttpOnly flag do? Prevents JavaScript from accessing the cookie via document.cookie. Protects against XSS-based cookie theft.

3. How do server-side sessions differ from JWT tokens? Sessions store data server-side with a session ID cookie. JWTs encode data in the token itself. Sessions can be revoked instantly; JWTs can’t.

4. What attacks does SameSite protect against? CSRF (Cross-Site Request Forgery) — prevents malicious sites from making authenticated requests on behalf of the user.

5. Challenge: Build an authentication system Create a Flask app with login, session management, and protected routes. Include CSRF protection and proper cookie attributes.

FAQ

What's the maximum size of a cookie?
4KB per cookie, with a limit of ~50 cookies per domain (varies by browser).
Are cookies sent to every request on the same domain?
Yes, unless restricted by Path or Domain attributes. To reduce overhead, use a separate subdomain for static assets.
How do third-party cookies work?
Third-party cookies are set by a domain different from the one you’re visiting (e.g., an ad tracker on a news site). They’re being phased out by major browsers.
Should I use sessions or JWT for my API?
Use JWT for stateless APIs and microservices. Use server sessions for traditional web apps where immediate revocation matters.

Try It Yourself

▶ Try It Yourself Edit the code and click Run

Mini Project: Session-Based Authentication

Build a complete login/logout system with Flask: user registration, password hashing (bcrypt), session management, protected routes, and CSRF protection on forms. Security angle: Doda Browser uses secure cookie storage with HttpOnly, Secure, and SameSite flags for all authentication cookies — preventing session hijacking even if an attacker finds an XSS vulnerability.

What’s Next

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

What’s Next

Congratulations on completing this Cookies and Sessions tutorial! Here’s where to go from here:

  • Practice daily — Inspect cookies in your browser’s DevTools
  • Build a project — Create a secure authentication system
  • Explore related topics — Check out CORS Complete Guide and HTTP Caching

Remember: every expert was once a beginner. Keep coding!

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro