Flask Sessions
A session stores data about a user across multiple requests. HTTP is stateless — each request arrives as if the server has never seen the user before. Sessions solve this by saving small pieces of data between visits, like whether a user is logged in or what items are in their cart.
The Hotel Key Card Analogy
When you check into a hotel, the front desk gives you a key card. The card does not contain your room number — it contains a code the hotel system recognizes. When you swipe the card, the system looks up your room. Flask sessions work the same way: the browser holds a session cookie (the key card), Flask looks up session data on the server side (the room assignment).
Browser stores: session cookie (encrypted ID) Flask stores: session data keyed to that ID Request arrives: Browser sends cookie ──▶ Flask decrypts ──▶ reads session data
How Flask Sessions Work
Flask stores session data in a signed cookie on the browser. The data is encoded and signed with your app's SECRET_KEY. Users can see the session data (it is Base64-encoded), but they cannot tamper with it — the signature breaks if they modify the contents.
Setting Up Sessions
Sessions require a secret key. Set it once in your app config:
app.config['SECRET_KEY'] = 'your-very-secret-key'In production, use a long random string and load it from an environment variable. A quick way to generate one:
python -c "import secrets; print(secrets.token_hex(32))"Writing to the Session
from flask import Flask, session, redirect, url_for
@app.route('/login', methods=['POST'])
def login():
username = request.form.get('username')
# verify credentials here ...
session['username'] = username
session['logged_in'] = True
return redirect(url_for('dashboard'))session behaves like a Python dictionary. Assign a key to store data. Flask saves it to the signed cookie automatically at the end of the request.
Reading from the Session
@app.route('/dashboard')
def dashboard():
if not session.get('logged_in'):
return redirect(url_for('login'))
username = session.get('username', 'Guest')
return f'<h1>Welcome, {username}!</h1>'Deleting Session Data
@app.route('/logout')
def logout():
session.pop('username', None)
session.pop('logged_in', None)
return redirect(url_for('home'))
# Or clear everything at once:
@app.route('/logout')
def logout():
session.clear()
return redirect(url_for('home'))Shopping Cart Example
@app.route('/cart/add/<int:product_id>')
def add_to_cart(product_id):
cart = session.get('cart', [])
if product_id not in cart:
cart.append(product_id)
session['cart'] = cart
session.modified = True # tell Flask the session changed
return redirect(url_for('cart'))
@app.route('/cart')
def cart():
cart_ids = session.get('cart', [])
products = Product.query.filter(Product.id.in_(cart_ids)).all()
return render_template('cart.html', products=products)Set session.modified = True when you modify a mutable object (like a list or dictionary) inside the session. Flask tracks simple assignments automatically, but not mutations inside nested objects.
Session Lifetime
from datetime import timedelta
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
@app.route('/login', methods=['POST'])
def login():
session.permanent = True # use the lifetime setting above
session['username'] = request.form.get('username')
return redirect(url_for('dashboard'))By default, sessions expire when the browser closes. Setting session.permanent = True keeps the session alive for the duration set in PERMANENT_SESSION_LIFETIME.
Session Security Notes
- Never store passwords or sensitive data in sessions
- Store only the user's ID; look up their data from the database on each request
- Use a strong, random
SECRET_KEYand keep it private - Rotate the secret key if you suspect it has been exposed (this invalidates all existing sessions)
Summary
Flask sessions store small amounts of user-specific data between requests using a signed cookie. Write to the session with session['key'] = value, read with session.get('key'), and clear with session.pop() or session.clear(). Sessions require a SECRET_KEY. Store only lightweight identifiers in sessions and load full user data from the database as needed.
