Flask - Sessions
Flask – Sessions
Section titled “Flask – Sessions”HTTP is a stateless protocol, meaning each request from a client to a server is treated independently. The server doesn’t inherently remember previous interactions with the same client. To maintain user-specific information across multiple requests (e.g., keeping a user logged in, storing shopping cart contents), we use sessions.
Unlike cookies, which store data directly in the user’s browser, Flask’s default session implementation uses signed cookies. This means the session data itself (like a username or user ID) is stored in a cookie sent to the client’s browser, but it’s cryptographically signed by the server using a secret key. This signature allows the server to verify that the session data hasn’t been tampered with by the client.
Because the data is stored client-side (in the signed cookie), this approach avoids the need for server-side storage for simple session data, making it scalable. However, it also means you shouldn’t store large amounts of data or highly sensitive information directly in the session, as cookies have size limits and the data (though signed) is still visible to the client.
To use sessions in Flask, you need to:
- Set a
SECRET_KEY: This is absolutely crucial for securely signing the session cookie. It should be a long, random, and unpredictable string kept secret. In production, load it from an environment variable or configuration management system, never hardcode it directly in your source code. - Import and use the
sessionobject: Flask makes the session available via thesessionobject imported fromflask. This object behaves like a Python dictionary.
Setting a session variable is straightforward:
from flask import session
# Example: Store the username after successful loginsession['username'] = 'admin'Reading a session variable:
# Check if the user is logged inif 'username' in session: username = session['username'] print(f"User {username} is logged in.")else: print("User is not logged in.")Removing a session variable (e.g., during logout):
# Remove 'username' from the session, return None if it doesn't existsession.pop('username', None)Let’s look at a simple login/logout example:
from flask import Flask, session, redirect, url_for, request, render_template_string
app = Flask(__name__)
# IMPORTANT: Set a strong, random secret key!# In a real app, load this from config/environment variable.app.config['SECRET_KEY'] = 'your-very-secure-and-random-secret-key'
# Simple in-memory user store for demonstrationusers = {'admin': 'password123'}
@app.route('/')def index(): if 'username' in session: username = session['username'] return f''' Logged in as **{username}**<br> <a href="{url_for('logout')}">Click here to log out</a> ''' return f''' You are not logged in.<br> <a href="{url_for('login')}">Click here to log in</a> '''
@app.route('/login', methods=['GET', 'POST'])def login(): if request.method == 'POST': submitted_user = request.form.get('username') submitted_pass = request.form.get('password')
# Basic validation (replace with proper password hashing in real apps!) if submitted_user in users and users[submitted_user] == submitted_pass: session['username'] = submitted_user return redirect(url_for('index')) else: # Invalid credentials, show form again with error (optional) error = 'Invalid username or password' return render_template_string(LOGIN_FORM, error=error)
# For GET request, just show the login form return render_template_string(LOGIN_FORM, error=None)
# Define the login form as a multi-line string constantLOGIN_FORM = """<!doctype html><title>Login</title><h1>Login</h1>{% if error %}<p style="color:red;">{{ error }}</p>{% endif %}<form method="post"> <p>Username: <input type=text name=username></p> <p>Password: <input type=password name=password></p> <p><input type=submit value=Login></p></form>"""
@app.route('/logout')def logout(): # Remove the username from the session if it's there session.pop('username', None) return redirect(url_for('index'))
if __name__ == '__main__': app.run(debug=True)How this example works:
/(index): Checks ifusernameexists in thesession. If yes, displays a welcome message and logout link. If not, displays a login link./login(GET): Displays a simple HTML login form (defined in theLOGIN_FORMstring and rendered usingrender_template_stringfor simplicity; usually you’d use a separate template file)./login(POST): Retrieves the username and password from the submitted form (request.form). It performs a very basic check against theusersdictionary (in a real application, you MUST hash passwords securely). If credentials are valid, it stores theusernamein thesessionand redirects to the index (/). If invalid, it redisplays the form with an error./logout: Removes theusernamefrom thesessionusingsession.pop()and redirects to the index.SECRET_KEY: Enables Flask to sign the session cookie securely.
Run this application (python app.py) and visit http://localhost:5000/. You’ll see the ‘not logged in’ message. Click the login link, enter ‘admin’ and ‘password123’, and submit. You’ll be redirected back to /, now showing the ‘Logged in as admin’ message. Clicking the logout link will clear the session, returning you to the ‘not logged in’ state.
Alternative Session Interfaces: While Flask’s default signed cookie session is convenient, it might not be suitable for all cases (e.g., storing large amounts of data, needing server-side invalidation). Flask extensions like Flask-Session allow you to configure different session backends, such as Redis, Memcached, SQLAlchemy (database), or the filesystem, which store session data server-side and only send a session ID cookie to the client.