How to Set Secure Session Cookie Flags in Flask
Session cookies are bearer tokens - whoever holds one is that user. Flask ships with insecure defaults on all three settings that matter: the secret key, HttpOnly, and Secure. Here's how to lock them down correctly.
Why the defaults are dangerous
Out of the box, a minimal Flask app often ends up with:
app.secret_key = "secret"
app.config["SESSION_COOKIE_HTTPONLY"] = False
app.config["SESSION_COOKIE_SECURE"] = False
Each line is its own attack vector:
- Weak secret key - Flask signs session cookies with HMAC-SHA1 using
secret_key. A guessable value like"secret"lets an attacker forge their own signed cookies, impersonating any user including admins. - HttpOnly missing - without
HttpOnly,document.cookiein JavaScript can read the session cookie. Any XSS injection - even a third-party script - can exfiltrate it. - Secure missing - without
Secure, the browser sends the session cookie over plain HTTP. On any network where traffic is visible (public Wi-Fi, corporate proxies, HTTP redirects), the cookie is intercepted in transit.
The fix: three config lines
import os
from flask import Flask
app = Flask(__name__)
# Load a strong secret from the environment - never hardcode
app.secret_key = os.environ["SESSION_SECRET"]
# Block JavaScript from reading the cookie (XSS protection)
app.config["SESSION_COOKIE_HTTPONLY"] = True
# Only send the cookie over HTTPS
app.config["SESSION_COOKIE_SECURE"] = True
Generate a strong secret key once and store it as an environment variable:
python3 -c "import secrets; print(secrets.token_hex(32))"
# -> 4f3a9c1b8e2d7f0a6c5b4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a
Use that output as SESSION_SECRET in your deployment environment (.env file,
Kubernetes secret, systemd EnvironmentFile, etc.). Never commit it to source control.
Verify the flags are present
After restarting the app, log in and inspect the Set-Cookie header:
curl -v -X POST http://localhost:8000/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}' 2>&1 | grep -i set-cookie
A correctly configured response looks like:
Set-Cookie: session=<signed-value>; HttpOnly; Path=/; Secure; SameSite=Lax
If HttpOnly or Secure are absent, the flags are not applied.
Go further: SameSite and cookie prefixes
SESSION_COOKIE_SAMESITE = "Lax"- blocks cross-site request forgery (CSRF) by preventing the cookie from being sent on cross-origin POST requests. Flask 2.x defaults to"Lax"; check you haven't overridden it to"None"without a reason.__Host-prefix - naming the cookie__Host-sessionforces the browser to enforce HTTPS-only and ignore aDomainattribute, providing an additional layer of protection on shared-domain deployments.- Rotate the secret key on a schedule or on suspected compromise. Rotation invalidates all existing sessions - plan for that in your logout/session-expiry flow.
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Loading secret_key from an environment variable instead of hardcoding it
- Setting SESSION_COOKIE_HTTPONLY and SESSION_COOKIE_SECURE to True in Flask config
- Verifying cookie flags with curl and inspecting the Set-Cookie header
FAQ
Why is a weak Flask secret_key dangerous?
Flask signs session cookies with HMAC using secret_key. If the key is guessable (e.g. 'secret', 'dev', an empty string), an attacker can forge valid signed cookies and impersonate any user. Always load the key from an environment variable and generate it with secrets.token_hex(32).
What does the HttpOnly cookie flag do?
HttpOnly tells the browser to block JavaScript from reading that cookie via document.cookie. Without it, any XSS injection on the page can silently steal the session token and send it to an attacker's server.
When should I set SESSION_COOKIE_SECURE to True?
Set it to True in any environment that serves over HTTPS - which is every production deployment. The Secure flag tells the browser never to send the cookie over plain HTTP, preventing interception on networks where traffic is visible.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →