Managing Session Lifetime and Persistence
To manage session lifetime and persistence in Flask, you use the SessionMixin attributes provided by the session object. These attributes allow you to control whether a session persists after the browser closes and track whether the session data has been read or changed during a request.
Making Sessions Permanent
By default, Flask sessions are "browser sessions," meaning they expire when the user closes their browser. To create a long-lived session, set session.permanent to True.
from flask import Flask, session
app = Flask(__name__)
app.secret_key = "example-key"
@app.route("/login")
def login():
# This session will now persist according to PERMANENT_SESSION_LIFETIME
session["user_id"] = 123
session.permanent = True
return "Logged in"
When permanent is True, Flask uses the PERMANENT_SESSION_LIFETIME configuration (default is 31 days) to set the cookie's expiration.
Tracking Session Access and Modification
Flask uses flags on the SessionMixin to optimize how and when it sends session cookies back to the client.
session.accessed: Automatically set toTruewhenever the session is read. If this isTrue, Flask adds aVary: Cookieheader to the response to ensure downstream caches handle the response correctly.session.modified: Set toTruewhenever a key is set or deleted in the session dictionary. Flask only sends aSet-Cookieheader ifmodifiedisTrue(or if the session is permanent andSESSION_REFRESH_EACH_REQUESTis enabled).
You can check these flags to see if the session was touched during a request:
@app.route("/check-session")
def check_session():
# Accessing the session sets 'accessed' to True
print(f"Accessed: {session.accessed}")
# Modifying the session sets 'modified' to True
session["last_visit"] = "now"
print(f"Modified: {session.modified}")
return "Checked"
Handling Nested Mutable Objects
Flask's default session implementation (based on werkzeug.datastructures.CallbackDict) only detects changes to the top-level session dictionary. If you modify a mutable object stored inside the session, such as a list or a dictionary, you must manually set session.modified = True.
@app.route("/add-item")
def add_item():
if "cart" not in session:
session["cart"] = []
# Modifying the list directly won't be detected by Flask
session["cart"].append("new-item")
# Manually signal that the session has changed
session.modified = True
return "Item added"
Custom Persistence Logic
If you implement a custom SessionInterface, you can use these flags in your save_session method to decide how to persist data. The SessionInterface provides helper methods that rely on these attributes:
should_set_cookie(): ReturnsTrueifsession.modifiedis set, or if the session is permanent and configured to refresh on every request.get_expiration_time(): Returns adatetimeobject ifsession.permanentisTrue, otherwise returnsNone.
from flask.sessions import SessionInterface, SessionMixin
class MySessionInterface(SessionInterface):
def save_session(self, app, session, response):
# Use the mixin's accessed flag to set Vary header
if session.accessed:
response.vary.add("Cookie")
# Use the mixin's modified flag to decide if we need to save
if not self.should_set_cookie(app, session):
return
# Use the mixin's permanent flag to calculate expiration
expires = self.get_expiration_time(app, session)
# ... logic to save session data and set cookie ...
Configuration Reference
The behavior of SessionMixin attributes is influenced by these application settings:
| Configuration | Default | Description |
|---|---|---|
PERMANENT_SESSION_LIFETIME | timedelta(days=31) | The duration of a session when session.permanent is True. |
SESSION_REFRESH_EACH_REQUEST | True | If True and the session is permanent, a Set-Cookie header is sent on every request to refresh the expiration. |
SESSION_COOKIE_NAME | "session" | The name of the cookie used to store the session. |