auth0-flask
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAuth0 Flask Web App Integration
Auth0 Flask Web应用集成
Add login, logout, and user profile to a Flask web application using .
auth0-server-python为Flask Web应用添加登录、登出和用户个人资料功能,使用实现。
auth0-server-pythonPrerequisites
前提条件
- 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 skill first
auth0-quickstart
- Flask应用
- 已配置Auth0常规Web应用(非API,必须是应用类型)
- 若尚未设置Auth0,请先使用技能
auth0-quickstart
When NOT to Use
不适用场景
- Python APIs with JWT Bearer validation — Use for FastAPI, or see the Django REST Framework quickstart
auth0-fastapi-api - FastAPI web app with login/logout UI — No dedicated skill yet; see the FastAPI quickstart
- Single Page Applications — Use ,
auth0-react, orauth0-vuefor client-side authauth0-angular - Next.js applications — Use which handles both client and server
auth0-nextjs - Node.js web apps — Use or
auth0-expressfor session-based authauth0-fastify
- 采用JWT Bearer验证的Python API —— 对于FastAPI,请使用,或查看Django REST Framework快速入门
auth0-fastapi-api - 带登录/登出UI的FastAPI Web应用 —— 暂无专用技能;请查看FastAPI快速入门
- 单页应用(SPA) —— 客户端身份验证请使用、
auth0-react或auth0-vueauth0-angular - Next.js应用 —— 使用,它同时支持客户端和服务器端
auth0-nextjs - Node.js Web应用 —— 基于会话的身份验证请使用或
auth0-expressauth0-fastify
Quick Start Workflow
快速开始流程
1. Install SDK
1. 安装SDK
bash
pip install auth0-server-python "flask[async]" python-dotenvCritical: You must install (not just ). The extra installs which is required for Flask 2.0+ to support route handlers. Without it, async routes will not work. In , use .
flask[async]flask[async]asgirefasync defrequirements.txtflask[async]>=2.0.0bash
pip install auth0-server-python "flask[async]" python-dotenv关键提示: 必须安装(而非仅)。扩展包会安装,这是Flask 2.0+支持路由处理器的必要依赖。没有它,异步路由将无法工作。在中,请使用。
flask[async]flask[async]asgirefasync defrequirements.txtflask[async]>=2.0.02. Configure Environment
2. 配置环境变量
Create :
.envbash
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/callbackAUTH0_DOMAINhttps://AUTH0_CLIENT_IDAUTH0_CLIENT_SECRETAUTH0_SECRETopenssl rand -hex 64创建文件:
.envbash
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/callbackAUTH0_DOMAINhttps://AUTH0_CLIENT_IDAUTH0_CLIENT_SECRETAUTH0_SECRETopenssl rand -hex 643. Configure Auth0 Dashboard
3. 配置Auth0控制台
In your Auth0 Application settings:
- Allowed Callback URLs:
http://localhost:5000/callback - Allowed Logout URLs:
http://localhost:5000
在你的Auth0应用设置中:
- 允许的回调URL:
http://localhost:5000/callback - 允许的登出URL:
http://localhost:5000
4. Create Auth Module
4. 创建身份验证模块
Create to initialize the with Flask session-based stores. The stores use Flask's built-in (cookie-based by default) for a stateless setup — no external database needed:
auth.pyServerClientsessionpython
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 instance and reuse it. Never hardcode credentials — always use environment variables.
ServerClientHow 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 or needed: The SDK supports passing (e.g. request/response objects) to store methods. Since these stores use — which is globally available during a request — they don't need anything from , so you can call SDK methods without passing it. If you implement a custom store that manages cookies directly (instead of using ), you would need to reintroduce with .
store_optionsbefore_requeststore_optionsflask.sessionstore_optionsflask.sessionstore_options{"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.
创建,使用Flask会话存储初始化。这些存储使用Flask内置的(默认基于Cookie)实现无状态设置——无需外部数据库:
auth.pyServerClientsessionpython
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() # 默认使用.env;若凭据在.env.local中,传入load_dotenv(".env.local")
class FlaskSessionStateStore(StateStore):
"""使用Flask会话进行持久化的状态存储。"""
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)
# 确保不返回字典,因为底层SDK期望StateData实例而非字典
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):
"""使用Flask会话进行持久化的事务存储。"""
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)
# 确保不返回字典,因为底层SDK期望TransactionData实例而非字典
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"},
)创建一个实例并复用。切勿硬编码凭据——始终使用环境变量。
ServerClient工作原理: Flask默认会话基于Cookie(无状态)。SDK在将会话数据(令牌、用户资料)存储到会话前,会用JWE加密,因此Cookie中的数据既签名又加密。无需服务器端数据库。
无需或: SDK支持将(如请求/响应对象)传递给存储方法。由于这些存储使用——它在请求期间全局可用——因此不需要中的任何内容,你可以直接调用SDK方法而无需传递它。如果你实现了一个直接管理Cookie的自定义存储(而非使用),则需要重新引入带有的。
store_optionsbefore_requeststore_optionsflask.sessionstore_optionsflask.session{"request": request, "response": response}store_optionsCookie大小说明: 无状态会话将所有数据存储在Cookie中(约4KB限制)。对于大多数应用来说这已足够。如果你存储大量会话数据或达到Cookie大小限制,请切换到有状态设置。
5. Configure Flask App
5. 配置Flask应用
In , set up Flask with the secret key and session configuration:
app.pypython
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: must be set for Flask session management. Without it, sessions won't work.
app.secret_keyFor production: Set when deploying with HTTPS. Leaving it as in production allows session cookies to be sent over unencrypted connections.
SESSION_COOKIE_SECURE=TrueFalse在中,设置Flask的密钥和会话配置:
app.pypython
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, # 生产环境设置为True(需要HTTPS)
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE="Lax",
)关键提示: 必须设置才能进行Flask会话管理。没有它,会话将无法工作。
app.secret_key生产环境注意: 使用HTTPS部署时,设置。生产环境中保持会允许会话Cookie通过未加密连接发送。
SESSION_COOKIE_SECURE=TrueFalse6. Add Home Route
6. 添加首页路由
python
@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>"python
@app.route("/")
async def home():
user = await auth0.get_user()
if user:
return f"Hello, {user['name']}! <a href='/profile'>个人资料</a> | <a href='/logout'>登出</a>"
return "欢迎!<a href='/login'>登录</a>"7. Add Login Route
7. 添加登录路由
python
@app.route("/login")
async def login():
authorization_url = await auth0.start_interactive_login()
return redirect(authorization_url)start_interactive_login()redirect()ServerClientpython
@app.route("/login")
async def login():
authorization_url = await auth0.start_interactive_login()
return redirect(authorization_url)start_interactive_login()redirect()ServerClient8. Add Callback Route
8. 添加回调路由
python
@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)}", 400Pass 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).
str(request.url)python
@app.route("/callback")
async def callback():
try:
await auth0.complete_interactive_login(str(request.url))
return redirect("/")
except Exception as e:
return f"身份验证错误:{str(e)}", 400将作为第一个参数传入——这是包含授权码查询参数的完整回调URL。始终用try/except包裹,因为令牌交换可能失败(例如,代码过期、CSRF不匹配)。
str(request.url)9. Add Profile Route (Protected)
9. 添加个人资料路由(受保护)
python
@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()Nonepython
@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>邮箱:{user['email']}</p>"
f"<img src='{user['picture']}' alt='{user['name']}' width='100' />"
f"<p><a href='/logout'>登出</a></p>"
)get_user()None10. Add Logout Route
10. 添加登出路由
python
@app.route("/logout")
async def logout():
url = await auth0.logout()
return redirect(url)logout()python
@app.route("/logout")
async def logout():
url = await auth0.logout()
return redirect(url)logout()11. Test the App
11. 测试应用
bash
flask runVisit to start the login flow.
http://localhost:5000/loginbash
flask run访问开始登录流程。
http://localhost:5000/loginStateful Setup with Redis
使用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.
对于生产应用或会话数据超过Cookie大小限制的情况,使用Flask-Session和Redis在服务器端存储会话。Cookie中仅存储会话ID。
1. Install Dependencies
1. 安装依赖
bash
pip install flask-session redisbash
pip install flask-session redis2. Configure Flask-Session
2. 配置Flask-Session
Update to use Redis-backed sessions:
app.pypython
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)更新以使用Redis支持的会话:
app.pypython
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
3. 无需修改存储
The same and from work without modification. Flask-Session transparently switches the backend from cookies to Redis — the stores continue to use as before.
FlaskSessionStateStoreFlaskSessionTransactionStoreauth.pyflask.sessionflask.sessionRoutes are identical to the stateless setup — no code changes needed.
auth.pyFlaskSessionStateStoreFlaskSessionTransactionStoreflask.sessionflask.session路由与无状态设置完全相同——无需修改代码。
Common Mistakes
常见错误
| Mistake | Fix |
|---|---|
Hardcoding | Always read from environment variables — never embed credentials in code |
Using | Not needed; |
Using | Not needed; the SDK manages sessions and authentication |
Manually parsing JWTs with | The SDK handles token validation internally |
Installing | Must use |
| Using synchronous route handlers | All routes calling SDK methods must be |
Forgetting | Required for Flask session management — without it, sessions silently fail |
Using | That package is for FastAPI APIs — use |
Passing | |
| Not configuring callback URL in Auth0 Dashboard | Must add |
Returning | It returns a URL string, not a response — must wrap in |
Not handling errors in | |
Calling SDK methods without | All SDK methods are async — forgetting |
Passing options positionally to | Use |
| Expecting backchannel logout to work | Not supported with cookie-based sessions — |
Deploying with | Must set to |
| 错误 | 修复方案 |
|---|---|
在源代码中硬编码 | 始终从环境变量读取——切勿在代码中嵌入凭据 |
直接使用 | 无需使用; |
使用 | 无需使用;SDK会管理会话和身份验证 |
手动用 | SDK会在内部处理令牌验证 |
安装不带 | 必须在requirements.txt中使用 |
| 使用同步路由处理器 | 所有调用SDK方法的路由必须是 |
忘记设置 | Flask会话管理必需——没有它,会话会静默失败 |
在Flask中使用 | 该包适用于FastAPI API——Flask请使用 |
将 | |
| 未在Auth0控制台配置回调URL | 必须将 |
直接返回 | 它返回的是URL字符串,而非响应——必须用 |
未在 | |
调用SDK方法时不带 | 所有SDK方法都是异步的——忘记 |
向 | 使用 |
| 期望后台登出生效 | 基于Cookie的会话不支持—— |
部署时设置 | 生产环境必须设置为True——否则Cookie会通过HTTP发送 |
Key SDK Methods
核心SDK方法
All methods are async:
| Method | Signature | Purpose |
|---|---|---|
| | Returns authorization URL string — wrap in |
| | Processes the callback URL, exchanges code for tokens |
| | Returns current session user dict or |
| | Returns the access token for calling external APIs |
| | Returns Auth0 logout URL string |
所有方法均为异步:
| 方法 | 签名 | 用途 |
|---|---|---|
| | 返回授权URL字符串——用 |
| | 处理回调URL,将授权码交换为令牌 |
| | 返回当前会话用户字典或 |
| | 返回用于调用外部API的访问令牌 |
| | 返回Auth0登出URL字符串 |
Related Skills
相关技能
- — For server-rendered Express web apps with login/logout sessions
auth0-express - — For Fastify web applications with session-based auth
auth0-fastify
- —— 适用于带登录/登出会话的服务器渲染Express Web应用
auth0-express - —— 适用于基于会话身份验证的Fastify Web应用
auth0-fastify
Quick Reference
快速参考
ServerClient configuration:
python
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:
python
user = await auth0.get_user()
if user is None:
return redirect("/login")Environment variables:
- — your Auth0 tenant domain (e.g.
AUTH0_DOMAIN)tenant.us.auth0.com - — your Application's client ID
AUTH0_CLIENT_ID - — your Application's client secret
AUTH0_CLIENT_SECRET - — encryption and session secret key
AUTH0_SECRET - — callback URL (e.g.
AUTH0_REDIRECT_URI)http://localhost:5000/callback
ServerClient配置:
python
auth0 = ServerClient(
domain=os.getenv("AUTH0_DOMAIN"), # 必填
client_id=os.getenv("AUTH0_CLIENT_ID"), # 必填
client_secret=os.getenv("AUTH0_CLIENT_SECRET"), # 必填
secret=os.getenv("AUTH0_SECRET"), # 必填(加密密钥)
redirect_uri=os.getenv("AUTH0_REDIRECT_URI"), # 必填
state_store=FlaskSessionStateStore(secret=secret), # 必填
transaction_store=FlaskSessionTransactionStore(secret=secret), # 必填
authorization_params={"scope": "openid profile email"}, # 推荐
)路由保护模式:
python
user = await auth0.get_user()
if user is None:
return redirect("/login")环境变量:
- —— 你的Auth0租户域名(例如
AUTH0_DOMAIN)tenant.us.auth0.com - —— 你的应用客户端ID
AUTH0_CLIENT_ID - —— 你的应用客户端密钥
AUTH0_CLIENT_SECRET - —— 加密与会话密钥
AUTH0_SECRET - —— 回调URL(例如
AUTH0_REDIRECT_URI)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
- 设置指南 - 自动化设置脚本、环境配置、Auth0 CLI使用
- 集成指南 - 受保护路由、API调用、会话管理、错误处理
- API参考 - 完整ServerClient API、配置选项、存储实现、安全说明