Session Cookie Security and Attributes
Flask manages session security and behavior through the SessionInterface and its default implementation, SecureCookieSessionInterface. This system determines how session data is serialized, signed, and sent to the browser as a cookie.
Core Session Configuration
The SessionInterface provides several methods that retrieve configuration values from the application's app.config. These values directly control the attributes of the session cookie sent in the Set-Cookie header.
| Config Key | Interface Method | Description |
|---|---|---|
SESSION_COOKIE_NAME | get_cookie_name | The name of the cookie (default: 'session'). |
SESSION_COOKIE_DOMAIN | get_cookie_domain | The domain for the cookie. If not set, it is only valid for the exact domain that set it. |
SESSION_COOKIE_PATH | get_cookie_path | The path for the cookie. Falls back to APPLICATION_ROOT or /. |
SESSION_COOKIE_HTTPONLY | get_cookie_httponly | If True (default), prevents client-side scripts from accessing the cookie. |
SESSION_COOKIE_SECURE | get_cookie_secure | If True, the cookie is only sent over HTTPS. |
SESSION_COOKIE_SAMESITE | get_cookie_samesite | Restricts cookie sending to same-site requests ('Lax', 'Strict', or None). |
SESSION_COOKIE_PARTITIONED | get_cookie_partitioned | If True, enables Cookies Having Independent Partitioned State (CHIPS). |
Security Flags and Attributes
The SecureCookieSessionInterface.save_session method uses these configurations to build the cookie. For example, the HttpOnly and Secure flags are critical for mitigating Cross-Site Scripting (XSS) and Man-in-the-Middle (MitM) attacks:
# Example configuration in tests/test_basic.py
app.config.update(
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_SAMESITE="Lax",
SESSION_COOKIE_PARTITIONED=True,
)
As of Flask 2.3, SESSION_COOKIE_DOMAIN no longer falls back to SERVER_NAME. If it is not explicitly set, browsers will restrict the cookie to the specific host that issued it, excluding subdomains.
Session Persistence and Expiration
The lifetime of a session is determined by the permanent attribute of the session object (defined in SessionMixin) and the get_expiration_time method.
- Browser Sessions: By default,
session.permanentisFalse. The cookie expires when the browser is closed. - Permanent Sessions: When
session.permanent = True, the cookie's expiration is set todatetime.now() + app.permanent_session_lifetime.
The should_set_cookie method determines if the Set-Cookie header should be included in the response:
def should_set_cookie(self, app: Flask, session: SessionMixin) -> bool:
return session.modified or (
session.permanent and app.config["SESSION_REFRESH_EACH_REQUEST"]
)
If SESSION_REFRESH_EACH_REQUEST is True (the default), permanent sessions will send a Set-Cookie header on every request to update the expiration time, even if the session data hasn't changed.
The Null Session and Secret Keys
Flask's default session implementation requires a SECRET_KEY to sign the cookie data using itsdangerous. If no secret key is configured, SecureCookieSessionInterface.open_session returns None, and the application falls back to a NullSession.
The NullSession (found in src/flask/sessions.py) allows reading but prevents modifications:
class NullSession(SecureCookieSession):
def _fail(self, *args: t.Any, **kwargs: t.Any) -> t.NoReturn:
raise RuntimeError(
"The session is unavailable because no secret "
"key was set. Set the secret_key on the "
"application to something unique and secret."
)
__setitem__ = __delitem__ = clear = pop = popitem = update = setdefault = _fail
Customizing Cookie Behavior
You can customize how session cookies are handled by subclassing SecureCookieSessionInterface. This is useful for dynamic requirements, such as changing the cookie name based on the request path.
In tests/test_reqctx.py, a custom interface is used to change the cookie name dynamically:
class PathAwareSessionInterface(SecureCookieSessionInterface):
def get_cookie_name(self, app):
if flask.request.url.endswith("dynamic_cookie"):
return "dynamic_cookie_name"
else:
return super().get_cookie_name(app)
app.session_interface = PathAwareSessionInterface()
Tracking Session Access
Flask tracks whether a session was accessed during a request via the accessed attribute in SessionMixin. If session.accessed is True, save_session automatically adds a Vary: Cookie header to the response. This informs caching proxies that the response content may vary based on the user's session cookie.
# From SecureCookieSessionInterface.save_session
if session.accessed:
response.vary.add("Cookie")