关于 auth0-flask
auth0-flask 是为 Flask Web 应用接入 Auth0 登录、登出和用户资料的技能,使用 auth0-server-python。它说明基于 Flask session 的无状态配置,也介绍 Redis 服务端会话方案。
主要功能
- 01配置 Auth0 交互式登录与回调
- 02读取用户资料并保护路由
- 03获取访问令牌并执行登出
- 04使用 Cookie 会话保存加密数据
- 05可选配置 Redis 服务端会话
适用场景
- 01为 Flask 应用添加登录和登出
- 02保护需要身份验证的页面
- 03在应用中获取用户资料或访问令牌
- 04会话数据超出 Cookie 限制时改用 Redis
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ auth0/ agent-skills --skill auth0-flask安装后在 Claude Code 中输入/auth0-flask确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api.mdintegration.mdsetup.mdtests/benchmark-config.jsonevals.jsongraders.jsonpackage.jsonprompt.mdrun-evals.mjs详细介绍
Auth0 Flask Web 应用集成
使用 auth0-server-python 为 Flask Web 应用添加登录、登出和用户资料功能。
前提条件
- Flask 应用
- 已配置 Auth0 Regular Web Application(不是 API,必须是 Application)
- 如果尚未设置 Auth0,请先使用
auth0-quickstart技能
不适用场景
- 使用 JWT Bearer 验证的 Python API — FastAPI 请使用
auth0-fastapi-api,或参阅 Django REST Framework 快速入门 - 带有登录/登出界面的 FastAPI Web 应用 — 目前还没有专用技能;请参阅 FastAPI 快速入门
- 单页应用 — 客户端身份验证请使用
auth0-react、auth0-vue或auth0-angular - Next.js 应用 — 请使用同时处理客户端和服务端的
auth0-nextjs - Node.js Web 应用 — 基于会话的身份验证请使用
auth0-express或auth0-fastify
快速入门工作流
1. 安装 SDK
pip install auth0-server-python "flask[async]" python-dotenv
重要: 必须安装 flask[async](不能只安装 flask)。[async] 扩展会安装 asgiref,这是 Flask 2.0+ 支持 async def 路由处理函数所必需的。缺少它时,异步路由将无法运行。在 requirements.txt 中使用 flask[async]>=2.0.0。
2. 配置环境
创建 .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 是你的 Auth0 租户域名(不含 https://)。AUTH0_CLIENT_ID 和 AUTH0_CLIENT_SECRET 来自 Auth0 Application 设置。AUTH0_SECRET 用于加密会话数据,可通过 openssl rand -hex 64 生成。
3. 配置 Auth0 控制面板
在 Auth0 Application 设置中:
- 允许的回调 URL:
http://localhost:5000/callback - 允许的登出 URL:
http://localhost:5000
4. 创建身份验证模块
创建 auth.py,使用基于 Flask 会话的存储初始化 ServerClient。存储使用 Flask 内置的 session(默认基于 Cookie),实现无状态配置,无需外部数据库:
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"},
)
创建一个 ServerClient 实例并重复使用。绝不要将凭证硬编码,始终使用环境变量。
工作原理: Flask 的默认会话基于 Cookie(无状态)。SDK 会先使用 JWE 加密会话数据(令牌、用户资料),再将其存储到会话中,因此 Cookie 中的数据既经过签名也经过加密。无需服务端数据库。
无需使用 store_options 或 before_request: SDK 支持向存储方法传入 store_options(例如请求/响应对象)。由于这些存储使用 flask.session(它在请求期间全局可用),因此不需要从 store_options 获取任何内容,你可以在调用 SDK 方法时不传入该参数。如果你实现了直接管理 Cookie 的自定义存储(而不是使用 flask.session),则需要重新引入 store_options,并传入 {"request": request, "response": response}。
Cookie 大小提示: 无状态会话会将所有数据存储在 Cookie 中(限制约为 4KB)。对于大多数应用来说,这已足够。如果你存储了大量会话数据或达到 Cookie 大小限制,请切换到有状态配置。
5. 配置 Flask 应用
在 app.py 中,使用密钥和会话配置设置 Flask:
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",
)
重要: 必须设置 app.secret_key,Flask 会话管理才能正常工作。没有它,会话将无法使用。
用于生产环境: 使用 HTTPS 部署时,请设置 SESSION_COOKIE_SECURE=True。在生产环境中将其设为 False,会导致会话 Cookie 通过未加密连接发送。
6. 添加主页路由
@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. 添加登录路由
@app.route("/login")
async def login():
authorization_url = await auth0.start_interactive_login()
return redirect(authorization_url)
start_interactive_login() 会返回一个指向 Auth0 Universal Login 页面的 URL 字符串。必须使用 redirect() 包装该 URL。授权参数(scope、redirect_uri)已在 ServerClient 上配置。
8. 添加回调路由
@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
将 str(request.url) 作为第一个参数传入——这是包含授权码查询参数的完整回调 URL。务必使用 try/except 包装,因为令牌交换可能失败(例如授权码过期、CSRF 不匹配)。
9. 添加个人资料路由(受保护)
@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() 会从会话中返回用户的个人资料;如果用户未登录,则返回 None。
10. 添加登出路由
@app.route("/logout")
async def logout():
url = await auth0.logout()
return redirect(url)
logout() 会返回 Auth0 登出 URL。将用户重定向到该 URL。
11. 测试应用
flask run
访问 http://localhost:5000/login 以启动登录流程。
使用 Redis 进行有状态配置
对于生产应用,或者会话数据超过 Cookie 大小限制时,请使用 Flask-Session 和 Redis 在服务端存储会话。Cookie 中只存储会话 ID。
1. 安装依赖项
pip install flask-session redis
2. 配置 Flask-Session
更新 app.py,以使用由 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. 无需更改存储
auth.py 中相同的 FlaskSessionStateStore 和 FlaskSessionTransactionStore 无需修改即可使用。Flask-Session 会透明地将 flask.session 后端从 Cookie 切换到 Redis——存储仍像之前一样使用 flask.session。
路由与无状态配置完全相同——无需更改代码。
常见错误
| 错误 | 修复方法 |
|---|---|
在源代码中硬编码 domain、client_id 或 client_secret | 始终从环境变量读取,绝不要在代码中嵌入凭据 |
直接使用 Authlib 或 python-jose | 无需使用;auth0-server-python 会处理所有 OAuth/OIDC 流程 |
使用 Flask-Login 或 Flask-Dance | 无需使用;SDK 会管理会话和身份验证 |
使用 jwt.decode() 手动解析 JWT | SDK 会在内部处理令牌验证 |
安装 flask 时未添加 [async] 附加项 | 必须在 requirements.txt 中使用 flask[async]>=2.0.0——否则,异步路由处理程序会静默失败 |
| 使用同步路由处理程序 | 所有调用 SDK 方法的路由都必须使用 async def 并配合 await |
忘记设置 app.secret_key | Flask 会话管理必需——未设置时,会话会静默失败 |
在 Flask 中使用 auth0-fastapi-api | 该包用于 FastAPI API;Flask 应使用 auth0-server-python |
将 domain 作为包含 https:// 的完整 URL 传入 | domain 应为纯域名,例如 my-tenant.us.auth0.com,而不是 https://my-tenant.us.auth0.com |
| 未在 Auth0 Dashboard 中配置回调 URL | 必须将 http://localhost:5000/callback 添加到 Allowed Callback URLs |
直接返回 start_interactive_login() | 它返回的是 URL 字符串,而不是响应;必须用 redirect() 包装 |
未处理 /callback 中的错误 | complete_interactive_login() 可能会失败;务必使用 try/except 包装 |
调用 SDK 方法时未使用 await | 所有 SDK 方法都是异步的;忘记使用 await 会返回协程,而不是结果 |
将选项作为位置参数传给 logout() | 使用 logout(store_options=...)——第一个位置参数是 LogoutOptions,而不是存储选项 |
| 预期后端通道登出能够正常工作 | 基于 Cookie 的会话不支持此功能——delete_by_logout_token 不执行任何操作。请使用标准的 /logout 路由 |
部署时设置 SESSION_COOKIE_SECURE=False | 生产环境中必须设为 True,否则 Cookie 会通过 HTTP 发送 |
SDK 关键方法
所有方法均为异步方法:
| 方法 | 签名 | 用途 |
|---|---|---|
start_interactive_login | await auth0.start_interactive_login() | 返回授权 URL 字符串 — 使用 redirect() 包装 |
complete_interactive_login | await auth0.complete_interactive_login(str(request.url)) | 处理回调 URL,并将授权码交换为令牌 |
get_user | await auth0.get_user() | 返回当前会话的用户字典或 None |
get_access_token | await auth0.get_access_token() | 返回用于调用外部 API 的访问令牌 |
logout | await auth0.logout() | 返回 Auth0 登出 URL 字符串 |
相关技能
auth0-express— 适用于带登录/登出会话的服务端渲染 Express Web 应用auth0-fastify— 适用于基于会话认证的 Fastify Web 应用auth0-cli— 在终端中管理 Auth0 资源
快速参考
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
)
路由保护模式:
user = await auth0.get_user()
if user is None:
return redirect("/login")
环境变量:
AUTH0_DOMAIN— 你的 Auth0 租户域名(例如tenant.us.auth0.com)AUTH0_CLIENT_ID— 你的应用客户端 IDAUTH0_CLIENT_SECRET— 你的应用客户端密钥AUTH0_SECRET— 加密和会话密钥AUTH0_REDIRECT_URI— 回调 URL(例如http://localhost:5000/callback)
详细文档
- 设置指南 - 自动化设置脚本、环境配置、Auth0 CLI 用法
- 集成指南 - 受保护路由、调用 API、会话管理、错误处理
- API 参考 - 完整的 ServerClient API、配置选项、存储实现、安全性