DEV Community

Cover image for Implementing Basic Session Management in a Lightweight Python Web Framework
HexShift
HexShift

Posted on

Implementing Basic Session Management in a Lightweight Python Web Framework

Sessions allow your web framework to maintain state between requests from the same client. This is crucial for features like login persistence, shopping carts, or user preferences.


What is a Session?

HTTP is stateless by design, meaning each request is independent. Sessions provide a way to associate multiple requests with a user by storing data on the server side and linking it via a session ID cookie.


How Sessions Work

  1. When a client connects, generate a unique session ID.
  2. Store session data on the server (in-memory, file, or database) keyed by that ID.
  3. Send the session ID back as a cookie.
  4. On subsequent requests, read the cookie to retrieve session data.

Generating Session IDs

Session IDs should be:

  • Unique
  • Hard to guess (secure)
  • Usually a long random string

Use Python’s secrets module:

import secrets

def generate_session_id():
    return secrets.token_hex(16)
Enter fullscreen mode Exit fullscreen mode

Storing Session Data

For a simple framework, use a dictionary:

sessions = {}
Enter fullscreen mode Exit fullscreen mode

Each session ID maps to a dict of user data:

sessions[session_id] = {"user_id": 123, "cart": []}
Enter fullscreen mode Exit fullscreen mode

Setting and Reading Cookies

When sending responses, include a Set-Cookie header:

Set-Cookie: session_id=abc123; Path=/; HttpOnly
Enter fullscreen mode Exit fullscreen mode

In incoming requests, parse the Cookie header:

def parse_cookies(headers):
    cookies = {}
    cookie_header = headers.get("Cookie", "")
    for pair in cookie_header.split(";"):
        if "=" in pair:
            key, value = pair.strip().split("=", 1)
            cookies[key] = value
    return cookies
Enter fullscreen mode Exit fullscreen mode

Middleware Example for Sessions

A middleware that loads or creates a session:

def session_middleware(request, next_handler):
    cookies = parse_cookies(request["headers"])
    session_id = cookies.get("session_id")

    if not session_id or session_id not in sessions:
        session_id = generate_session_id()
        sessions[session_id] = {}

    request["session"] = sessions[session_id]
    response = next_handler(request)

    # Add Set-Cookie header if new session created
    if "Set-Cookie" not in response.get("headers", {}):
        response.setdefault("headers", {})["Set-Cookie"] = f"session_id={session_id}; Path=/; HttpOnly"
    return response
Enter fullscreen mode Exit fullscreen mode

Using Sessions in Handlers

Handlers can access request["session"] to read or write session data:

def dashboard(request):
    user = request["session"].get("user")
    if not user:
        return {"status": 401, "body": b"Unauthorized"}
    return {"status": 200, "body": f"Welcome, {user}".encode()}
Enter fullscreen mode Exit fullscreen mode

Security Considerations

  • Use HttpOnly and Secure flags on cookies where appropriate
  • Implement session expiration and cleanup
  • Consider storing sessions outside memory for scalability
  • Protect against session fixation and hijacking

Wrap-Up

Adding basic session support to your lightweight framework enables persistent user experiences. While simple in concept, proper session management is key to building real-world web applications.

Want to dive deeper? Check out my 20-page PDF guide: Building a Lightweight Python Web Framework from Scratch

Top comments (0)