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:
sessionbehaves like a dict stored in a signed cookie by defaultsession.permanent = TrueusesPERMANENT_SESSION_LIFETIMEinstead of browser-session expiry
Configure lifetime:
from datetime import timedelta
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(days=7)Server-Side vs Client-Side Sessions
| Type | Storage | Pros | Cons |
|---|---|---|---|
| Signed cookie (Flask default) | Browser cookie | Simple, no extra service | Size limit ~4KB; data visible (but signed) |
| Server-side (Redis, DB) | Server store | Large data, instant revoke | Needs 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:
{% 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 themwith_categories=truereturns(category, message)tuples for CSS styling
Multiple flashes:
flash("Item added.", "info")
flash("Cart total updated.", "info")Reading and Writing Cookies Directly
Set cookie on response:
Read cookie:
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:
resp.set_cookie("theme", "dark", secure=True, httponly=True, samesite="Lax")Code explanation:
httponly=Trueblocks JavaScript from reading the cookie (mitigates XSS theft)secure=Truesends cookie only over HTTPSsamesite="Lax"reduces CSRF risk on cross-site requests
Session vs Flash vs Cookie
| Feature | Purpose | Typical data |
|---|---|---|
| session | Multi-request server-backed state | user_id, preferences |
| flash | One-time UI messages | "Saved!", errors after redirect |
| Cookie | Client-readable or custom tokens | Theme, analytics (non-sensitive) |
Modify Session Safely
Mark session modified when changing mutable objects:
session["cart"] = session.get("cart", [])
session["cart"].append(item_id)
session.modified = TrueFlask 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.