4.9. Sessions in Flask#

Flask provides a built-in way to manage user sessions using the flask.session object. Flask’s session implementation is more general than simply logging in users. It can be used to store any data we like, including a user identifier.

From the flask documentation:

This is implemented on top of cookies for you and signs the cookies cryptographically. What this means is that the user could look at the contents of your cookie but not modify it, unless they know the secret key used for signing.

https://flask.palletsprojects.com/en/stable/quickstart/#sessions.

We can learn two important points about Flask’s session implementation from the quote:

  • they are client-side sessions

  • session data is securely signed using a secret key, preventing tampering.

4.9.1. Setting Session Data#

Within a Flask route function you can access the session object. This object can be treated as a dictionary.

In the example below, there is a login route that sets the "user_id" value to 12345.

from flask import Flask, session, request, redirect, url_for

app = Flask(__name__)
app.config["SECRET_KEY"] = "supersecretkey"  # Required for cookie signing


@app.route("/login")
def login():
    session["user_id"] = 12345  # Store user ID in session
    return redirect(url_for("index"))

4.9.2. Getting Session Data#

Retrieving data from the session is the same as using a dictionary. You can check for the existence of keys using in and index into the dictionary using the key name.

In the example below, the user_id is retrieved to display a user specific message.

from flask import Flask, session, request, redirect, url_for

app = Flask(__name__)
app.config["SECRET_KEY"] = "supersecretkey"  # Required for cookie signing


@app.route("/")
def index():
    if "user_id" in session:
        user_id = session["user_id"]
        return "Logged in as user {}".format(user_id)
    return "Not logged in"

4.9.3. Removing Session Data#

To remove data from the session use pop.

In the example below, pop is used to log a user out.

from flask import Flask, session, request, redirect, url_for

app = Flask(__name__)
app.config["SECRET_KEY"] = "supersecretkey"  # Required for cookie signing


@app.route("/logout")
def logout():
    session.pop("user_id")  # Remove session data
    return redirect(url_for("index"))

4.9.4. Expiration#

By default Flask session data is only valid for the browser session. It will be deleted once the browser window closes.

This behavior can be changed by setting:

  • a value for the PERMANENT_SESSION_LIFETIME configuration parameter

  • setting the session.permanent attribute to True

In the example below, session.permanent is set during the log-in and set to 60 minutes.

from datetime import timedelta
from flask import Flask, session, request, redirect, url_for

app = Flask(__name__)
app.config["SECRET_KEY"] = "supersecretkey"  # Required for cookie signing
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(minutes=60)


@app.route("/login")
def login():
    session.permanent = True
    session["user_id"] = 12345  # Store user ID in session
    return redirect(url_for("index"))

More details here https://flask.palletsprojects.com/en/stable/api/#flask.session.permanent.

4.9.5. Security Considerations#

  • SECRET_KEY

    • This value must be kept private. Any disclosure of this value could lead to an attacker setting their own value for the cookies and signing it.

    • This value should be hard to guess. Use a CSPRNG to generate it.

  • Private Data

    • Do not store any private or sensitive data in the session object. It is transmitted as plain text.

  • Session Hijacking

    • If an attacker obtains any of the session cookie values, they can attach them to their own requests to impersonate a user.

    • To protect against attackers intercepting the cookies make sure to serve your site over HTTPS and restrict the cookie to be served over HTTPS only by setting "SESSION_COOKIE_SECURE" to True

  • Cross Site Scripting

    • We will learn more about this in a later module, but it can be prevented by setting "SESSION_COOKIE_HTTPONLY" to True.

Recommended settings are:

app.config["SECRET_KEY"] = "supersecretkey"  # Keep this private
app.config["SESSION_COOKIE_SECURE"] = True  # Only send over HTTPS
app.config["SESSION_COOKIE_HTTPONLY"] = True  # Prevent JavaScript access