
auth0-flask
★ 37by auth0 · part of auth0/agent-skills
Use when adding login, logout, and user profile to a Flask web application using session-based authentication - integrates auth0-server-python for…
Use when adding login, logout, and user profile to a Flask web application using session-based authentication - integrates auth0-server-python for…
Inspect the full instructions your agent will receiveExpandCollapse
This is the exact playbook injected into your agent when the skill activates — shown here so you can audit it before installing. You don't need to read it to use the skill.
by auth0
Use when adding login, logout, and user profile to a Flask web application using session-based authentication - integrates auth0-server-python for…
npx skills add https://github.com/auth0/agent-skills --skill auth0-flask
Download ZIPGitHub37
Auth0 Flask Web App Integration
Add login, logout, and user profile to a Flask web application using auth0-server-python.
When NOT to Use
-
Python APIs with JWT Bearer validation — Use
auth0-fastapi-apifor FastAPI, or see the Django REST Framework quickstart -
FastAPI web app with login/logout UI — No dedicated skill yet; see the FastAPI quickstart
-
Single Page Applications — Use
auth0-react,auth0-vue, orauth0-angularfor client-side auth -
Next.js applications — Use
auth0-nextjswhich handles both client and server -
Node.js web apps — Use
auth0-expressorauth0-fastifyfor session-based auth
Key SDK Methods
All methods are async:
Method Signature Purpose
start_interactive_login await auth0.start_interactive_login() Returns authorization URL string — wrap in redirect()
complete_interactive_login await auth0.complete_interactive_login(str(request.url)) Processes the callback URL, exchanges code for tokens
get_user await auth0.get_user() Returns current session user dict or None
get_access_token await auth0.get_access_token() Returns the access token for calling external APIs
logout await auth0.logout() Returns Auth0 logout URL string
Related Skills
-
auth0-express— For server-rendered Express web apps with login/logout sessions -
auth0-fastify— For Fastify web applications with session-based auth -
auth0-cli— Manage Auth0 resources from the terminal
Quick Reference
ServerClient configuration:
auth0 = ServerClient(
domain=os.getenv("AUTH0_DOMAIN"), # required
client_id=os.getenv("AUTH0_CLIENT_ID"), # required
client_secret=os.getenv("AUTH0_CLIENT_SECRET"), # required
secret=os.getenv("AUTH0_SECRET"), # required (encryption secret)
redirect_uri=os.getenv("AUTH0_REDIRECT_URI"), # required
state_store=FlaskSessionStateStore(secret=secret), # required
transaction_store=FlaskSessionTransactionStore(secret=secret), # required
authorization_params={"scope": "openid profile email"}, # recommended
)
Route protection pattern:
user = await auth0.get_user()
if user is None:
return redirect("/login")
Environment variables:
-
AUTH0_DOMAIN— your Auth0 tenant domain (e.g.tenant.us.auth0.com) -
AUTH0_CLIENT_ID— your Application's client ID -
AUTH0_CLIENT_SECRET— your Application's client secret -
AUTH0_SECRET— encryption and session secret key -
AUTH0_REDIRECT_URI— callback URL (e.g.http://localhost:5000/callback)
Detailed Documentation
-
Setup Guide - Automated setup scripts, environment configuration, Auth0 CLI usage
-
Integration Guide - Protected routes, calling APIs, session management, error handling
-
API Reference - Complete ServerClient API, configuration options, store implementation, security
References
pip install auth0-server-python "flask[async]" python-dotenvRun this in your project — your agent picks the skill up automatically.
Prerequisites
-
Flask application
-
Auth0 Regular Web Application configured (not an API — must be an Application)
-
If you don't have Auth0 set up yet, use the
auth0-quickstartskill first
Quick Start Workflow
1. Install SDK
pip install auth0-server-python "flask[async]" python-dotenv
Critical: You must install flask[async] (not just flask). The [async] extra installs asgiref which is required for Flask 2.0+ to support async def route handlers. Without it, async routes will not work. In requirements.txt, use flask[async]>=2.0.0.
2. Configure Environment
Create .env:
AUTH0_DOMAIN=your-tenant.us.auth0.com
AUTH0_CLIENT_ID=your_client_id
AUTH0_CLIENT_SECRET=your_client_secret
AUTH0_SECRET=your_generated_app_secret
AUTH0_REDIRECT_URI=http://localhost:5000/callback
AUTH0_DOMAIN is your Auth0 tenant domain (without https://). AUTH0_CLIENT_ID and AUTH0_CLIENT_SECRET come from your Auth0 Application settings. AUTH0_SECRET is used for encrypting session data — generate with openssl rand -hex 64.
3. Configure Auth0 Dashboard
In your Auth0 Application settings:
-
Allowed Callback URLs:
http://localhost:5000/callback -
Allowed Logout URLs:
http://localhost:5000
4. Create Auth Module
Create auth.py to initialize the ServerClient with Flask session-based stores. The stores use Flask's built-in session (cookie-based by default) for a stateless setup — no external database needed:
import os
from flask import session as flask_session
from auth0_server_python.auth_server.server_client import ServerClient
from auth0_server_python.auth_types import StateData, TransactionData
from auth0_server_python.store import StateStore, TransactionStore
from dotenv import load_dotenv
load_dotenv() # Uses .env by default; pass load_dotenv(".env.local") if credentials are in .env.local
class FlaskSessionStateStore(StateStore):
"""State store that uses Flask's session for persistence."""
def __init__(self, secret: str):
super().__init__({"secret": secret})
async def set(self, identifier, state, remove_if_expires=False, options=None):
data = state.dict() if hasattr(state, "dict") else state
flask_session[identifier] = self.encrypt(identifier, data)
async def get(self, identifier, options=None):
data = flask_session.get(identifier)
if data is None:
return None
decrypted = self.decrypt(identifier, data)
# Ensure to not return a dict, as the underlying SDK expects a StateData instance, not a dict
return StateData(**decrypted) if isinstance(decrypted, dict) else decrypted
async def delete(self, identifier, options=None):
flask_session.pop(identifier, None)
async def delete_by_logout_token(self, claims, options=None):
pass
class FlaskSessionTransactionStore(TransactionStore):
"""Transaction store that uses Flask's session for persistence."""
def __init__(self, secret: str):
super().__init__({"secret": secret})
async def set(self, identifier, state, remove_if_expires=False, options=None):
data = state.dict() if hasattr(state, "dict") else state
flask_session[identifier] = self.encrypt(identifier, data)
async def get(self, identifier, options=None):
data = flask_session.get(identifier)
if data is None:
return None
decrypted = self.decrypt(identifier, data)
# Ensure to not return a dict, as the underlying SDK expects a TransactionData instance, not a dict
return TransactionData(**decrypted) if isinstance(decrypted, dict) else decrypted
async def delete(self, identifier, options=None):
flask_session.pop(identifier, None)
secret = os.getenv("AUTH0_SECRET")
auth0 = ServerClient(
domain=os.getenv("AUTH0_DOMAIN"),
client_id=os.getenv("AUTH0_CLIENT_ID"),
client_secret=os.getenv("AUTH0_CLIENT_SECRET"),
secret=secret,
redirect_uri=os.getenv("AUTH0_REDIRECT_URI"),
state_store=FlaskSessionStateStore(secret=secret),
transaction_store=FlaskSessionTransactionStore(secret=secret),
authorization_params={"scope": "openid profile email"},
)
Create one ServerClient instance and reuse it. Never hardcode credentials — always use environment variables.
How this works: Flask's default session is cookie-based (stateless). The SDK encrypts session data (tokens, user profile) with JWE before storing it in the session, so data is both signed and encrypted in the cookie. No server-side database is required.
No store_options or before_request needed: The SDK supports passing store_options (e.g. request/response objects) to store methods. Since these stores use flask.session — which is globally available during a request — they don't need anything from store_options, so you can call SDK methods without passing it. If you implement a custom store that manages cookies directly (instead of using flask.session), you would need to reintroduce store_options with {"request": request, "response": response}.
Cookie size note: Stateless sessions store all data in a cookie (~4KB limit). For most apps this is sufficient. If you store large amounts of session data or hit cookie size limits, switch to stateful setup .
5. Configure Flask App
In app.py, set up Flask with the secret key and session configuration:
import os
from flask import Flask, redirect, request
from auth import auth0
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__)
app.secret_key = os.getenv("AUTH0_SECRET")
app.config.update(
SESSION_COOKIE_SECURE=False, # Set to True in production (requires HTTPS)
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE="Lax",
)
Critical: app.secret_key must be set for Flask session management. Without it, sessions won't work.
For production: Set SESSION_COOKIE_SECURE=True when deploying with HTTPS. Leaving it as False in production allows session cookies to be sent over unencrypted connections.
6. Add Home Route
@app.route("/")
async def home():
user = await auth0.get_user()
if user:
return f"Hello, {user['name']}! Profile | Logout "
return "Welcome! Login "
7. Add Login Route
@app.route("/login")
async def login():
authorization_url = await auth0.start_interactive_login()
return redirect(authorization_url)
start_interactive_login() returns a URL string pointing to Auth0's Universal Login page. You must wrap it in redirect(). Authorization params (scope, redirect_uri) are already configured on the ServerClient.
8. Add Callback Route
@app.route("/callback")
async def callback():
try:
await auth0.complete_interactive_login(str(request.url))
return redirect("/")
except Exception as e:
return f"Authentication error: {str(e)}", 400
Pass str(request.url) as the first argument — this is the full callback URL including the authorization code query parameters. Always wrap in try/except since the token exchange can fail (e.g. expired code, CSRF mismatch).
9. Add Profile Route (Protected)
@app.route("/profile")
async def profile():
user = await auth0.get_user()
if user is None:
return redirect("/login")
return (
f"
# {user['name']}
"
f" Email: {user['email']}
"
f" "
f" Logout
"
)
get_user() returns the user's profile from the session, or None if not logged in.
10. Add Logout Route
@app.route("/logout")
async def logout():
url = await auth0.logout()
return redirect(url)
logout() returns the Auth0 logout URL. Redirect the user to it.
11. Test the App
flask run
Visit http://localhost:5000/login to start the login flow.
Stateful Setup with Redis
For production apps or when session data exceeds cookie size limits, use Flask-Session with Redis to store sessions server-side. Only a session ID is stored in the cookie.
1. Install Dependencies
pip install flask-session redis
2. Configure Flask-Session
Update app.py to use Redis-backed sessions:
import os
from flask import Flask, redirect, request
from flask_session import Session
from auth import auth0
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__)
app.secret_key = os.getenv("AUTH0_SECRET")
app.config.update(
SESSION_TYPE="redis",
SESSION_PERMANENT=True,
SESSION_KEY_PREFIX="auth0:",
SESSION_COOKIE_SECURE=False,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE="Lax",
)
Session(app)
3. No Store Changes Needed
The same FlaskSessionStateStore and FlaskSessionTransactionStore from auth.py work without modification. Flask-Session transparently switches the flask.session backend from cookies to Redis — the stores continue to use flask.session as before.
Routes are identical to the stateless setup — no code changes needed.
Common Mistakes
Mistake Fix
Hardcoding domain, client_id, or client_secret in source Always read from environment variables — never embed credentials in code
Using Authlib or python-jose directly Not needed; auth0-server-python handles all OAuth/OIDC flows
Using Flask-Login or Flask-Dance Not needed; the SDK manages sessions and authentication
Manually parsing JWTs with jwt.decode() The SDK handles token validation internally
Installing flask without [async] extra Must use flask[async]>=2.0.0 in requirements.txt — without it, async route handlers silently fail
Using synchronous route handlers All routes calling SDK methods must be async def and use await
Forgetting app.secret_key Required for Flask session management — without it, sessions silently fail
Using auth0-fastapi-api in Flask That package is for FastAPI APIs — use auth0-server-python for Flask
Passing domain as full URL with https:// domain should be the bare domain, e.g. my-tenant.us.auth0.com, not https://my-tenant.us.auth0.com
Not configuring callback URL in Auth0 Dashboard Must add http://localhost:5000/callback to Allowed Callback URLs
Returning start_interactive_login() directly It returns a URL string, not a response — must wrap in redirect()
Not handling errors in /callback complete_interactive_login() can fail — always wrap in try/except
Calling SDK methods without await All SDK methods are async — forgetting await returns a coroutine instead of the result
Passing options positionally to logout() Use logout(store_options=...) — the first positional parameter is LogoutOptions, not store options
Expecting backchannel logout to work Not supported with cookie-based sessions — delete_by_logout_token is a no-op. Use standard /logout route
Deploying with SESSION_COOKIE_SECURE=False Must set to True in production — cookies are sent over HTTP otherwise