100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Python

Session Management in Flask

Understand how Flask's signed cookie-based sessions work, their limitations, and how to configure them securely.

APIs & AuthIntermediate9 min readJul 10, 2026
Analogies

How Flask Sessions Actually Work

Flask's built-in session object is not server-side storage by default — it's a dictionary-like structure that gets serialized, cryptographically signed with itsdangerous using app.secret_key, and sent to the browser as a single cookie. The signature prevents tampering (the browser can't forge or alter values without invalidating the signature), but the data itself is only base64-encoded, not encrypted, meaning anyone can decode and read the cookie's contents even though they can't modify it undetected — so sensitive data should never be placed directly in the session.

🏏

Cricket analogy: A signed-but-unencrypted session cookie is like a scorecard sealed with an official stamp: anyone can read the printed numbers on it, but nobody can alter a run total without breaking the tamper-evident seal — Flask's session is readable but not silently editable.

Configuring Secure Session Cookies

Several app.config keys govern session cookie behavior: SESSION_COOKIE_SECURE (only send the cookie over HTTPS), SESSION_COOKIE_HTTPONLY (prevents JavaScript from reading the cookie, mitigating XSS-based theft — enabled by default), SESSION_COOKIE_SAMESITE ('Lax' or 'Strict' to limit cross-site request forgery exposure), and PERMANENT_SESSION_LIFETIME (how long a session marked session.permanent = True remains valid). Setting session.permanent = True is required for PERMANENT_SESSION_LIFETIME to take effect at all; without it, Flask treats the cookie as a browser-session cookie that expires when the browser closes.

🏏

Cricket analogy: SESSION_COOKIE_HTTPONLY is like restricting who can physically handle the official scorebook — commentators can view the displayed score, but only the appointed scorer can touch the book itself, preventing unauthorized edits, just as HttpOnly blocks JavaScript from reading the cookie.

python
from datetime import timedelta
from flask import Flask, session

app = Flask(__name__)
app.secret_key = 'load-this-from-an-environment-variable'

app.config.update(
    SESSION_COOKIE_SECURE=True,      # only send over HTTPS
    SESSION_COOKIE_HTTPONLY=True,    # block JS access (default True)
    SESSION_COOKIE_SAMESITE='Lax',   # mitigate CSRF
    PERMANENT_SESSION_LIFETIME=timedelta(days=7),
)

@app.route('/set-preference/<theme>')
def set_preference(theme):
    session.permanent = True  # required for PERMANENT_SESSION_LIFETIME to apply
    session['theme'] = theme
    return {'theme': session['theme']}, 200

@app.route('/clear-session')
def clear_session():
    session.clear()
    return {'message': 'session cleared'}, 200

Server-Side Sessions with Flask-Session

Because the default client-side session is limited in size (cookies typically cap around 4KB) and visible to the client, applications that need to store larger or more sensitive session data often switch to the Flask-Session extension, which keeps the actual session payload in a backend store — Redis, filesystem, SQLAlchemy, or Memcached — and sends the browser only a small opaque session ID as the cookie. This flips the security model: the cookie itself no longer needs to be readable-but-safe, since it carries no meaningful data, and revoking a session becomes as simple as deleting its record from the backend store, which isn't possible with pure signed-cookie sessions since a previously issued cookie remains valid until it expires.

🏏

Cricket analogy: Switching to server-side sessions is like moving from carrying a physical printed pass with your details on it to a barcode that only references a record in the stadium's central database — lose the barcode and security can instantly deactivate that specific record, unlike a printed pass that stays valid until it physically expires.

Flask-Session's default filesystem backend is fine for local development but doesn't scale across multiple server processes or machines; production deployments typically use a shared backend like Redis so every app instance sees the same session store.

Client-side (default) Flask sessions cannot be forcibly invalidated server-side before their expiration — once issued, a signed cookie stays valid until it expires or the secret_key changes (which invalidates every session at once). If you need per-session revocation (e.g. a 'log out all devices' feature), you need server-side sessions or a token-tracking mechanism.

  • Flask's default session is a signed, client-side cookie — tamper-evident via itsdangerous, but not encrypted, so its contents are readable by anyone with the cookie.
  • Never store sensitive data (passwords, secrets, full PII) directly in the session; store only small, non-sensitive identifiers.
  • SESSION_COOKIE_SECURE, SESSION_COOKIE_HTTPONLY, and SESSION_COOKIE_SAMESITE configure cookie transport and access security.
  • session.permanent = True is required for PERMANENT_SESSION_LIFETIME to actually apply.
  • Client-side sessions cannot be individually revoked before expiration; only rotating secret_key invalidates all sessions at once.
  • Flask-Session enables server-side storage (Redis, filesystem, database) with only an opaque ID sent to the browser, allowing per-session revocation.
  • Production deployments generally need a shared backend (like Redis) rather than the filesystem backend to work correctly across multiple server processes.

Practice what you learned

Was this page helpful?

Topics covered

#Python#FlaskStudyNotes#WebDevelopment#SessionManagementInFlask#Session#Management#Flask#Sessions#StudyNotes#SkillVeris