Skip to main content

Configuring Session Cookie Attributes

To customize the behavior of session cookies—such as restricting them to HTTPS, setting a specific domain, or enabling SameSite policies—you update the SESSION_COOKIE_* keys in the Flask application configuration.

Flask's SessionInterface uses these configuration values to determine how the Set-Cookie header is constructed when saving a session.

Basic Configuration

You can configure all session cookie attributes at once using app.config.update. This is common when setting up an application for a specific environment (e.g., production).

from flask import Flask

app = Flask(__name__)
app.secret_key = "a-very-secret-key"

app.config.update(
SESSION_COOKIE_NAME="my_session",
SESSION_COOKIE_DOMAIN=".example.com",
SESSION_COOKIE_PATH="/",
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_SAMESITE="Lax",
SESSION_COOKIE_PARTITIONED=True,
)

Scoping Cookies by Domain and Path

The scope of a session cookie determines which requests the browser will include the cookie in.

Domain Scoping

Use SESSION_COOKIE_DOMAIN to control which domains and subdomains can access the session.

  • If not set (default None), the cookie is valid only for the exact domain that set it.
  • If set to a domain like .example.com, the cookie is sent to that domain and all its subdomains.

The SessionInterface.get_cookie_domain method retrieves this value.

[!IMPORTANT] As of Flask 2.3, SESSION_COOKIE_DOMAIN no longer falls back to SERVER_NAME. If it is not explicitly set, it defaults to None.

Path Scoping

Use SESSION_COOKIE_PATH to restrict the cookie to a specific URL prefix.

  • If not set, Flask falls back to APPLICATION_ROOT.
  • If APPLICATION_ROOT is also not set, it defaults to /.

The SessionInterface.get_cookie_path method handles this fallback logic.

Security Flags

Flask provides several flags to harden session cookies against common web vulnerabilities.

HTTPOnly

SESSION_COOKIE_HTTPONLY (default True) prevents client-side scripts (like JavaScript) from accessing the cookie. This is a primary defense against Cross-Site Scripting (XSS) attacks that attempt to steal session tokens.

This is retrieved via SessionInterface.get_cookie_httponly.

Secure

SESSION_COOKIE_SECURE (default False) instructs the browser to only send the cookie over encrypted (HTTPS) connections. You should always set this to True in production.

This is retrieved via SessionInterface.get_cookie_secure.

SameSite

SESSION_COOKIE_SAMESITE (default None) controls the SameSite attribute, which helps prevent Cross-Site Request Forgery (CSRF) attacks. Valid values are:

  • "Strict": Cookie is only sent for first-party requests.
  • "Lax": Cookie is sent for first-party requests and safe top-level navigations (like links).
  • None: Cookie is sent for all requests (requires Secure=True in most browsers).

This is retrieved via SessionInterface.get_cookie_samesite.

Partitioned Cookies (CHIPS)

For applications that need to support Cookies Having Independent Partitioned State (CHIPS), set SESSION_COOKIE_PARTITIONED to True. This allows the session cookie to be used when the site is embedded in an <iframe> on a different top-level site.

app.config["SESSION_COOKIE_PARTITIONED"] = True

This attribute was added in Flask 3.1 and is retrieved via SessionInterface.get_cookie_partitioned.

Session Lifetime and Persistence

By default, session cookies are "session cookies" in the browser sense—they expire when the browser is closed. You can make them "permanent" so they persist across browser restarts.

Enabling Permanent Sessions

To use a persistent cookie, set session.permanent = True within a request and configure PERMANENT_SESSION_LIFETIME.

from datetime import timedelta
from flask import session

app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(days=31)

@app.route("/login")
def login():
session["user_id"] = 1
session.permanent = True
return "Logged in"

The SessionInterface.get_expiration_time method calculates the timestamp for the Expires and Max-Age cookie attributes based on this configuration.

The SESSION_REFRESH_EACH_REQUEST (default True) setting determines if the Set-Cookie header is sent on every request for permanent sessions.

  • If True, the expiration time is extended on every response.
  • If False, the cookie is only sent if the session is modified.

The SessionInterface.should_set_cookie method implements this logic:

# Internal logic in SessionInterface.should_set_cookie
return session.modified or (
session.permanent and app.config["SESSION_REFRESH_EACH_REQUEST"]
)

Troubleshooting

Flask only sends a Set-Cookie header if:

  1. The session has been modified (e.g., session["key"] = value).
  2. The session is marked as permanent and SESSION_REFRESH_EACH_REQUEST is True.
  3. The session was deleted (the cookie is cleared).

If you find the cookie is not updating, ensure you are actually modifying the session object or have enabled the refresh setting.

Invalid SameSite Value

If you set SESSION_COOKIE_SAMESITE to a value other than "Strict", "Lax", or None, Flask will raise a ValueError during the response processing phase.

# This will cause a ValueError when a request is handled
app.config["SESSION_COOKIE_SAMESITE"] = "InvalidValue"