Intégration Auth0 avec Flask Web App
Ajoutez la connexion, la déconnexion et le profil utilisateur à une application web Flask en utilisant auth0-server-python.
Prérequis
- Application Flask
- Application Web Régulière Auth0 configurée (pas une API — doit être une Application)
- Si vous n'avez pas encore configuré Auth0, utilisez d'abord la skill
auth0-quickstart
Quand NE PAS l'utiliser
- APIs Python avec validation JWT Bearer — Utilisez
auth0-fastapi-apipour FastAPI, ou consultez le quickstart Django REST Framework - Application web FastAPI avec UI de connexion/déconnexion — Pas de skill dédiée pour le moment ; consultez le quickstart FastAPI
- Applications monopage — Utilisez
auth0-react,auth0-vueouauth0-angularpour l'authentification côté client - Applications Next.js — Utilisez
auth0-nextjsqui gère à la fois le client et le serveur - Applications web Node.js — Utilisez
auth0-expressouauth0-fastifypour l'authentification basée sur les sessions
Workflow de démarrage rapide
1. Installer le SDK
pip install auth0-server-python "flask[async]" python-dotenv
Critique : Vous devez installer flask[async] (pas seulement flask). L'extra [async] installe asgiref qui est requis pour Flask 2.0+ afin de supporter les gestionnaires de route async def. Sans cela, les routes asynchrones ne fonctionneront pas. Dans requirements.txt, utilisez flask[async]>=2.0.0.
2. Configurer l'environnement
Créez .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 est votre domaine de locataire Auth0 (sans https://). AUTH0_CLIENT_ID et AUTH0_CLIENT_SECRET proviennent des paramètres de votre Application Auth0. AUTH0_SECRET est utilisé pour chiffrer les données de session — générez avec openssl rand -hex 64.
3. Configurer le tableau de bord Auth0
Dans les paramètres de votre Application Auth0 :
- Allowed Callback URLs :
http://localhost:5000/callback - Allowed Logout URLs :
http://localhost:5000
4. Créer un module d'authentification
Créez auth.py pour initialiser le ServerClient avec des magasins basés sur la session Flask. Les magasins utilisent la session intégrée de Flask (basée sur les cookies par défaut) pour une configuration sans état — aucune base de données externe requise :
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"},
)
Créez une instance ServerClient et réutilisez-la. Ne codez jamais les identifiants en dur — utilisez toujours les variables d'environnement.
Comment cela fonctionne : La session par défaut de Flask est basée sur les cookies (sans état). Le SDK chiffre les données de session (tokens, profil utilisateur) avec JWE avant de les stocker dans la session, donc les données sont à la fois signées et chiffrées dans le cookie. Aucune base de données côté serveur n'est requise.
Pas de store_options ou before_request nécessaires : Le SDK supporte le passage de store_options (par exemple, objets request/response) aux méthodes de magasin. Puisque ces magasins utilisent flask.session — qui est disponible globalement pendant une requête — ils n'ont besoin de rien de store_options, vous pouvez donc appeler les méthodes du SDK sans le passer. Si vous implémentez un magasin personnalisé qui gère directement les cookies (au lieu d'utiliser flask.session), vous devriez réintroduire store_options avec {"request": request, "response": response}.
Note sur la taille des cookies : Les sessions sans état stockent toutes les données dans un cookie (limite ~4 KB). Pour la plupart des applications, c'est suffisant. Si vous stockez de grandes quantités de données de session ou dépassez les limites de taille des cookies, passez à la configuration avec état.
5. Configurer l'application Flask
Dans app.py, configurez Flask avec la clé secrète et la configuration de session :
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",
)
Critique : app.secret_key doit être défini pour la gestion des sessions Flask. Sans cela, les sessions ne fonctionneront pas.
Pour la production : Définissez SESSION_COOKIE_SECURE=True lors du déploiement avec HTTPS. Le laisser à False en production permet aux cookies de session d'être envoyés sur des connexions non chiffrées.
6. Ajouter la route d'accueil
@app.route("/")
async def home():
user = await auth0.get_user()
if user:
return f"Hello, {user['name']}! <a href='/profile'>Profile</a> | <a href='/logout'>Logout</a>"
return "Welcome! <a href='/login'>Login</a>"
7. Ajouter la route de connexion
@app.route("/login")
async def login():
authorization_url = await auth0.start_interactive_login()
return redirect(authorization_url)
start_interactive_login() retourne une chaîne URL pointant vers la page Universal Login d'Auth0. Vous devez l'envelopper dans redirect(). Les paramètres d'autorisation (scope, redirect_uri) sont déjà configurés sur le ServerClient.
8. Ajouter la route de callback
@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
Passez str(request.url) comme premier argument — c'est l'URL complète de callback, y compris les paramètres de requête du code d'autorisation. Enveloppez toujours dans try/except puisque l'échange de tokens peut échouer (par exemple, code expiré, non-concordance CSRF).
9. Ajouter la route de profil (protégée)
@app.route("/profile")
async def profile():
user = await auth0.get_user()
if user is None:
return redirect("/login")
return (
f"<h1>{user['name']}</h1>"
f"<p>Email: {user['email']}</p>"
f"<img src='{user['picture']}' alt='{user['name']}' width='100' />"
f"<p><a href='/logout'>Logout</a></p>"
)
get_user() retourne le profil de l'utilisateur depuis la session, ou None s'il n'est pas connecté.
10. Ajouter la route de déconnexion
@app.route("/logout")
async def logout():
url = await auth0.logout()
return redirect(url)
logout() retourne l'URL de déconnexion Auth0. Redirigez l'utilisateur vers celle-ci.
11. Tester l'application
flask run
Visitez http://localhost:5000/login pour démarrer le flux de connexion.
Configuration avec état avec Redis
Pour les applications de production ou quand les données de session dépassent les limites de taille des cookies, utilisez Flask-Session avec Redis pour stocker les sessions côté serveur. Seul un ID de session est stocké dans le cookie.
1. Installer les dépendances
pip install flask-session redis
2. Configurer Flask-Session
Mettez à jour app.py pour utiliser des sessions sauvegardées par Redis :
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. Aucun changement de magasin nécessaire
Les mêmes FlaskSessionStateStore et FlaskSessionTransactionStore de auth.py fonctionnent sans modification. Flask-Session bascule de manière transparente le backend de flask.session des cookies à Redis — les magasins continuent à utiliser flask.session comme avant.
Les routes sont identiques à la configuration sans état — aucun changement de code nécessaire.
Erreurs courantes
| Erreur | Solution |
|---|---|
Codage en dur de domain, client_id ou client_secret dans le code source |
Lisez toujours depuis les variables d'environnement — n'intégrez jamais les identifiants dans le code |
Utiliser Authlib ou python-jose directement |
Non nécessaire ; auth0-server-python gère tous les flux OAuth/OIDC |
Utiliser Flask-Login ou Flask-Dance |
Non nécessaire ; le SDK gère les sessions et l'authentification |
Parser manuellement les JWTs avec jwt.decode() |
Le SDK gère la validation des tokens en interne |
Installer flask sans l'extra [async] |
Doit utiliser flask[async]>=2.0.0 dans requirements.txt — sans cela, les gestionnaires de route asynchrones échouent silencieusement |
| Utiliser des gestionnaires de route synchrones | Tous les routes appelant les méthodes du SDK doivent être async def et utiliser await |
Oublier app.secret_key |
Requis pour la gestion des sessions Flask — sans cela, les sessions échouent silencieusement |
Utiliser auth0-fastapi-api dans Flask |
Ce package est pour les APIs FastAPI — utilisez auth0-server-python pour Flask |
Passer domain en tant qu'URL complète avec https:// |
domain doit être le domaine nu, par exemple my-tenant.us.auth0.com, pas https://my-tenant.us.auth0.com |
| Ne pas configurer l'URL de callback dans le tableau de bord Auth0 | Doit ajouter http://localhost:5000/callback à Allowed Callback URLs |
Retourner start_interactive_login() directement |
Elle retourne une chaîne URL, pas une réponse — doit envelopper dans redirect() |
Ne pas gérer les erreurs dans /callback |
complete_interactive_login() peut échouer — enveloppez toujours dans try/except |
Appeler les méthodes du SDK sans await |
Toutes les méthodes du SDK sont asynchrones — oublier await retourne une coroutine au lieu du résultat |
Passer les options positivement à logout() |
Utilisez logout(store_options=...) — le premier paramètre positionnel est LogoutOptions, pas les options de magasin |
| S'attendre à ce que la déconnexion backchannel fonctionne | Non supportée avec les sessions basées sur les cookies — delete_by_logout_token est une no-op. Utilisez la route /logout standard |
Déployer avec SESSION_COOKIE_SECURE=False |
Doit définir à True en production — les cookies sont envoyés sur HTTP sinon |
Méthodes clés du SDK
Toutes les méthodes sont asynchrones :
| Méthode | Signature | Objectif |
|---|---|---|
start_interactive_login |
await auth0.start_interactive_login() |
Retourne une chaîne URL d'autorisation — enveloppez dans redirect() |
complete_interactive_login |
await auth0.complete_interactive_login(str(request.url)) |
Traite l'URL de callback, échange le code contre les tokens |
get_user |
await auth0.get_user() |
Retourne le dictionnaire utilisateur de session actuel ou None |
get_access_token |
await auth0.get_access_token() |
Retourne le token d'accès pour appeler les APIs externes |
logout |
await auth0.logout() |
Retourne la chaîne URL de déconnexion Auth0 |
Skills associées
auth0-express— Pour les applications web Express serveur-rendu avec sessions de connexion/déconnexionauth0-fastify— Pour les applications Fastify avec authentification basée sur les sessions
Référence rapide
Configuration du ServerClient :
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
)
Motif de protection des routes :
user = await auth0.get_user()
if user is None:
return redirect("/login")
Variables d'environnement :
AUTH0_DOMAIN— votre domaine de locataire Auth0 (par exempletenant.us.auth0.com)AUTH0_CLIENT_ID— l'ID client de votre ApplicationAUTH0_CLIENT_SECRET— le secret client de votre ApplicationAUTH0_SECRET— clé secrète de chiffrement et de sessionAUTH0_REDIRECT_URI— URL de callback (par exemplehttp://localhost:5000/callback)
Documentation détaillée
- Guide de configuration - Scripts de configuration automatisés, configuration de l'environnement, utilisation de l'Auth0 CLI
- Guide d'intégration - Routes protégées, appel d'APIs, gestion des sessions, gestion des erreurs
- Référence API - API complète ServerClient, options de configuration, implémentation des magasins, sécurité