Session, Flash, and Cookies

Introduction

HTTP is stateless—each request stands alone. Sessions remember users across requests (login state, cart). Flash messages show one-time feedback after redirects. Cookies store small client-side data. Flask signs session data with SECRET_KEY so clients cannot tamper with it.

Prerequisites

Flask Sessions

Code explanation:

  • session behaves like a dict stored in a signed cookie by default
  • session.permanent = True uses PERMANENT_SESSION_LIFETIME instead of browser-session expiry

Configure lifetime:

python
from datetime import timedelta
 
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(days=7)

Server-Side vs Client-Side Sessions

TypeStorageProsCons
Signed cookie (Flask default)Browser cookieSimple, no extra serviceSize limit ~4KB; data visible (but signed)
Server-side (Redis, DB)Server storeLarge data, instant revokeNeeds Redis/DB setup

Flask default is client-side signed—payload is serialized and signed, not encrypted. Do not store passwords in session.

Tip

Store IDs, Not Secrets

Keep user_id in session; load user details from the database per request or use Flask-Login (later chapter).

Flash Messages

templates/settings.html:

html
{% with messages = get_flashed_messages(with_categories=true) %}
  {% if messages %}
    <ul class="flash-list">
      {% for category, message in messages %}
        <li class="flash-{{ category }}">{{ message }}</li>
      {% endfor %}
    </ul>
  {% endif %}
{% endwith %}

Code explanation:

  • flash() stores messages in session until the next request reads them
  • with_categories=true returns (category, message) tuples for CSS styling

Multiple flashes:

python
flash("Item added.", "info")
flash("Cart total updated.", "info")

Reading and Writing Cookies Directly

Set cookie on response:

Read cookie:

python
from flask import Flask, request
 
app = Flask(__name__)
 
@app.route("/")
def index():
    theme = request.cookies.get("theme", "light")
    return f"Current theme: {theme}"

Production HTTPS:

python
resp.set_cookie("theme", "dark", secure=True, httponly=True, samesite="Lax")

Code explanation:

  • httponly=True blocks JavaScript from reading the cookie (mitigates XSS theft)
  • secure=True sends cookie only over HTTPS
  • samesite="Lax" reduces CSRF risk on cross-site requests
FeaturePurposeTypical data
sessionMulti-request server-backed stateuser_id, preferences
flashOne-time UI messages"Saved!", errors after redirect
CookieClient-readable or custom tokensTheme, analytics (non-sensitive)

Modify Session Safely

Mark session modified when changing mutable objects:

python
session["cart"] = session.get("cart", [])
session["cart"].append(item_id)
session.modified = True

Flask may not detect in-place list changes without session.modified = True.

FAQ

Session not persisting?

Check SECRET_KEY is stable across restarts—changing it invalidates all sessions.

Flash shows twice?

Ensure template calls get_flashed_messages() once per request.

Session too large?

Cookie sessions have size limits—store only IDs; use server-side session for big data.

Delete one session key?

session.pop("user_id", None)

Flash without redirect?

Works on same request render—common pattern is redirect after POST (PRG).

Session secret leaked?

Rotate SECRET_KEY—all users must log in again.