关于 auth0-to-descope
面向工程师的 Auth0 到 Descope 认证迁移技能。它将 MCP 检查、代码分析和可审阅的迁移计划与实际执行分开,只有计划获批后才开始修改代码。
主要功能
- 01检查 Descope Docs MCP 是否可用
- 02收集迁移需求
- 03定位认证代码触点
- 04生成供审阅的 MIGRATION-PLAN.md
- 05仅在计划获批后执行
适用场景
- 01规划从 Auth0 迁移到 Descope
- 02在实施前审阅认证变更
- 03核对特定框架的迁移细节
MCP 相关
该技能会检查 Descope Docs MCP,并在迁移期间使用其文档工具核实 SDK 细节。若 MCP 不可用,会询问是否安装或在没有它的情况下继续。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ descope/ skills --skill auth0-to-descope安装后在 Claude Code 中输入/auth0-to-descope确认已加载。
附带文件references/flows-and-widgets.mdreferences/implementation-nuances.md
详细介绍
Auth0 → Descope 迁移技能
此技能用于指导从 Auth0 迁移到 Descope 的自助式迁移。分为三个部分:
- MCP 检查 — 确认 Descope Docs MCP 是否可用;如果不可用,则建议安装
- 迁移计划 — 通过分类问题收集背景信息,分析代码库中的身份验证触点,并生成便于用户阅读的
MIGRATION-PLAN.md供其审核 - 执行 — 如果用户确认要继续,则执行计划
不要将这些部分合并,也不要跳过步骤。开始更改代码前,必须先审核计划。
主要参考资料(均位于此技能的目录中):
references/implementation-nuances.md— 各框架经过验证的迁移模式、Auth0 功能到 Descope 的映射,以及已知问题references/flows-and-widgets.md— Descope 术语、Flow 结构和模板、Widget、SSO Setup Suite,以及 Console 与代码的决策指南
指导原则
优先使用 Console。 在为任何面向用户的身份验证功能推荐 SDK 代码前,先检查 Console、Flow 或 Widget 是否能满足使用场景。工程师只需集成一次(设置 SDK + 验证会话)。此后所有身份验证方面的演进——新方法、MFA 变更、UI 更新——都应在 Console 中完成,无需部署代码。参见 references/flows-and-widgets.md → Console 与代码。
先询问,不要假设。 在任何设计决策点——嵌入 Flow 与 OIDC 兼容性、Flow 与自定义代码、Widget 与自定义页面、内联 MFA 与单独注册、程序化 SSO 与 SSO Setup Suite——都应使用 AskUserQuestion,而不是带着假设继续操作。错误假设的代价会随着涉及的 20 多个文件不断累积。对于架构或意图方面的不确定性,始终值得提出问题。
优先使用 MCP,而非依赖记忆。 如果 Docs MCP 可用(已在第 1 部分确认),在编写 SDK 方法名、选项结构和返回类型前,使用 ask-question-about-descope 逐一核实。不要以“请根据 SDK 类型声明核实确切的方法名”来规避验证——直接核实即可。
第 1 部分:MCP 检查(阻塞步骤)
在进行其他操作前,调用 search-descope-docs 并使用简单查询(例如“会话验证”),检查 Descope Docs MCP 是否可用。
如果工具可用: 立即进入第 2 部分。
如果工具不可用,请显示以下消息,并使用 AskUserQuestion 询问用户是否想先安装:
尚未安装 Descope Docs MCP。
此技能会在迁移过程中使用 Descope Docs MCP 查询最新的 API 签名、SDK 方法和功能可用性。如果没有它,指导将基于静态训练数据,可能已经过时,也可能导致生成不存在的 SDK 调用。
你可以在几分钟内通过 https://docs-mcp.descope.com/ 安装(服务 URL:
https://docs-mcp.descope.com/mcp)。它能显著提高迁移结果的准确性,尤其是在查询 SDK 和配置特定 Flow 时。你想先安装 MCP 再继续,还是不安装直接继续?
- 如果用户选择安装:暂停并等待。用户确认安装完成后,再次调用
search-descope-docs检查,然后继续。 - 如果用户选择不安装直接继续:继续操作,但将任何 SDK 特定的回答标注为“基于目前已知的文档——请对照当前 SDK 核实”。
此步骤解决前,不要进入第 2 部分。
第 2 部分:迁移计划
第 2 部分包含两个子步骤:
- 分类 — 提出了解迁移范围所需的问题(迁移相关问题应在此处提出,因为答案会影响计划)
- 代码库分析 + 计划文件 — 扫描项目,生成
MIGRATION-PLAN.md,然后暂停等待审核
步骤 0:分流(阻塞性——需要使用 AskUserQuestion)
使用 AskUserQuestion 工具收集以下信息。不要根据记忆、之前的对话或假设推断答案——即使你认为自己知道答案也不行。
迁移路径会根据这些答案而有所不同;弄错会浪费用户的时间,并给出错误的指导。
在用户回答之前,不要继续执行步骤 0.5。
第一次调用 AskUserQuestion(最多 4 个问题):
- 后端语言 / 框架——根据对话中的任何线索,提供最可能的选项(例如 Express、Next.js、Flask/FastAPI、Go)。用户始终可以选择“其他”。
- 迁移目标——完全切换、增量 / 分阶段迁移,还是仅进行评估。
- 现有用户群体——他们是在迁移一款已有 Auth0 活跃用户的应用,还是从头开始?这决定是否需要规划用户迁移(密码哈希、批量导入、分阶段切换还是一次性切换、切换时强制重新登录)。
- 偏好的迁移方式——他们希望直接嵌入 Descope Flows/Widgets(完全原生迁移),还是保留现有的 OIDC 客户端库,并将其指向 Descope 的 OIDC 端点(OIDC 兼容层)?注意:B2B 功能(Organizations/SSO/SCIM 管理)没有 OIDC 层的对应方案,无论采用哪种路径都需要调用原生 SDK。
第二次调用 AskUserQuestion——Auth0 功能使用情况(使用 multiSelect: true):
-
目前在使用哪些 Auth0 功能? 提供影响最大的类别:
- Actions / Rules / Hooks(自定义登录逻辑)
- Organizations(多租户 / B2B)
- FGA / 精细化授权
- 社交登录 / 企业 SSO
用户可以通过“其他”补充功能。针对选中的项目进行追问——例如,如果选择了 Organizations,则询问租户级 SSO、SCIM 和邀请相关情况。如果选择了 FGA,则询问授权模型。
此外,如尚未涉及,请通过后续的
AskUserQuestion询问:- Token Vault / Connected Accounts 的使用情况
- M2M / 客户端凭据应用
- 自定义电子邮件模板、Log Streams、Attack Protection、自定义域名
完成两次调用后,总结调查结果,并在继续执行步骤 0.5 前标出复杂度较高的项目(CIBA、Token Vault、FGA)。
步骤 0.5:工程师审查检查点(阻塞性——需要 AskUserQuestion)
这些问题旨在发现框架未能揭示的阻塞因素。即使你认为自己知道答案,也要询问。开始分析代码库前,先使用 AskUserQuestion。
每次最多将 4 个问题合并为一组。根据步骤 0 的回答,跳过明显不适用的问题(例如,如果用户表示要从头开始,就跳过用户迁移规划)。
访问权限和凭据
- 他们能访问 Descope Console 并拥有 Project ID 吗?(如果不能,请参阅步骤 1.5。)
- 他们需要 Management Key 吗?(用户 CRUD、角色管理、ReBAC 和 Outbound Apps 均需要。)
代码库范围
- 应用中是否有地方直接从会话令牌读取声明(例如
token.email、req.auth.permissions)?这些代码要正常运行,需要先配置 JWT Template。 - 他们是否使用 Auth0 Actions、Rules 或 Hooks?每一个都需要在 Descope Flow 步骤或 JWT Template 中重新实现。
- 是否有多个服务或微服务在验证 Auth0 令牌?每个服务都需要更新为验证 Descope JWT。
部署和风险
- 他们是否有多个环境(dev / staging / prod)?每个环境都需要独立的 Descope 项目和 Project ID。
- 是否有维护窗口,还是必须做到零停机?
用户迁移(如果他们在步骤 0 中表示已有用户)
- 用户有多少?少于 1,000 个时,迁移脚本可以直接从 Auth0 API 拉取数据。超过 1,000 个时,Auth0 API 的分页会出问题;他们需要先通过 Auth0 的 User Import/Export 扩展导出 JSON 文件。
- 他们是否使用密码?如果是,他们需要向 Auth0 提交支持工单以获取密码哈希导出文件——这需要时间,应提前规划。如果没有哈希,用户就需要重置密码或改用无密码登录。
- 是一次性整体切换,还是分阶段切换?为实现零中断,Descope 支持会话迁移(beta)——可将活跃的 Auth0 会话转换为 Descope 令牌,无需重新验证,但用户必须已存在于 Descope 中。若分阶段切换,可在 Flow 条件中使用
freshlyMigrated自定义属性(由迁移脚本自动设置),为迁移后首次登录的用户提供特殊的引导流程。 - 他们是否了解,如果不使用会话迁移,切换时 Auth0 会话将失效?请规划强制重新登录或分阶段发布。
- 指引他们使用
descope/descope-migration脚本(步骤 3),并建议在正式运行前先进行试运行(--dry-run)。
需要立即指出的缺口(不要提问——根据步骤 0 的回答主动指出)
- 如果他们使用 CIBA 或
@auth0/ai封装:继续之前先指出这一点——Descope 没有对应功能,需要自定义实现(参见步骤 3)。 - 如果他们在 AI Agent 中使用 Auth0 Token Vault:迁移复杂度为 Medium;目前没有 SDK 封装。
- 如果他们使用 Auth0 Log Streams:切换前设置 Descope 的 Audit Webhook Connector,避免事件日志记录出现缺口。
Console/Flow/Widget 的替代方案(在分析代码库前指出,然后提问)
- 如果应用有自定义 SSO 设置页面:询问 SSO Setup Suite + Tenant Profile Widget 是否可以替代相关代码。
- 如果应用有个人资料编辑页面或用户管理界面:询问 Descope Widget 是否能满足该用例。
- 如果应用有单独的 MFA 注册页面:询问是否应将 MFA 作为步骤或子流程集成到主登录 Flow 中(在 Descope 中,这样通常更简洁)。
- 如果有任何服务端代码会生成电子邮件、发起 SSO 或在身份验证流程中运行逻辑:询问这些逻辑是否可以改为 Flow 步骤或 Connector,而不是使用服务端代码。
在继续分析代码库前,总结所有阻塞因素以及 Console/Flow 的替代方案。
第 1 步:分析代码库
在编写计划前,扫描代码库,梳理所有身份验证相关触点。
运行以下搜索(根据用户使用的语言调整文件扩展名):
# Find all Auth0 import sites
grep -rn "auth0\|@auth0\|express-openid-connect\|nextjs-auth0\|auth0-fastapi\|go-oidc" \
--include="*.ts" --include="*.tsx" --include="*.js" --include="*.py" --include="*.go" \
--exclude-dir=node_modules --exclude-dir=.next --exclude-dir=dist --exclude-dir=venv \
. 2>/dev/null
# Find all Auth0 env var references
grep -rn "AUTH0_\|auth0\." \
--include="*.ts" --include="*.tsx" --include="*.js" --include="*.py" --include="*.go" \
--include="*.env*" --include="*.yml" --include="*.yaml" --include="Dockerfile" \
--exclude-dir=node_modules --exclude-dir=.next \
. 2>/dev/null
# Find claim / token access patterns (things that may need JWT Template)
grep -rn "token\.\|claims\.\|req\.auth\.\|req\.oidc\.\|session()\." \
--include="*.ts" --include="*.tsx" --include="*.js" --include="*.py" --include="*.go" \
--exclude-dir=node_modules --exclude-dir=.next \
. 2>/dev/null
# Find protected route declarations
grep -rn "requiresAuth\|withPageAuthRequired\|withApiAuthRequired\|require_session\|@login_required\|authMiddleware\|isAuthenticated" \
--include="*.ts" --include="*.tsx" --include="*.js" --include="*.py" --include="*.go" \
--exclude-dir=node_modules --exclude-dir=.next \
. 2>/dev/null
# Check package.json / go.mod / requirements.txt for Auth0 dependencies
find . -maxdepth 3 \( -name "package.json" -o -name "go.mod" -o -name "requirements.txt" \) \
! -path "*/node_modules/*" -exec grep -l "auth0" {} \;
对于每个匹配项,记录:
- 文件路径和行号 — 变更发生的位置
- 用途 — 导入、路由保护、声明访问、注销处理程序等
- 复杂度 — 低(可直接替换)、中(需要重写逻辑)、高(没有等效方案)
阅读 package.json(或等效文件),确认确切的框架版本——这会影响异步行为(Next.js 15 与 14)和 SDK 兼容性。
如果可以使用 Descope Docs MCP,请使用 search-descope-docs 或 ask-question-about-descope,验证计划中准备引用的 SDK 方法名称是否为当前版本。
第 2 步:编写 MIGRATION-PLAN.md
根据分诊答案和代码库分析,在工作目录中编写 MIGRATION-PLAN.md。
计划面向两类读者:工程师需要足够的技术细节来执行;PM 或技术负责人需要了解范围、风险和时间安排,而无需解读术语。使用通俗英语。每个章节开头先用一句话概述其含义,再呈现表格或证据。首次出现技术术语时解释其含义。说明遗漏风险会造成什么后果,而不只是指出风险存在。为复杂度标签配上时间估算;估算尽量偏向较低值——SDK 替换和机械式重写通常比预想的耗时更短,而同一组中的重复文件在处理完第一个后会快得多。将执行工作分成多个阶段,明确哪些工作可以并行,哪些必须按顺序完成。
计划必须包含以下章节,并按此顺序排列:
概览
用 2–3 句话说明要替换什么、由什么接替,以及推荐采用的方案和一句话理由。再用一句话说明哪些内容保持不变——面向用户的登录行为、会话和现有账户都会保留。
包含 迁移概览 表格:
| 方案 | 完全原生迁移 / OIDC 兼容层 |
| 变更文件 | N 个源文件,涉及 N 个领域 |
| 控制台设置 | 上线前需要完成 N 项配置 |
| 用户影响 | 无需重新登录 / 切换后用户需要登录一次 |
| 预计工程投入 | N–N 小时 |
| 最大风险 | 用一句话指出复杂度最高的事项 |
变更内容及原因
用文字(而非表格)描述系统中各部分目前的作用,以及迁移后的作用。例如:
目前,Auth0 负责所有与登录相关的工作:显示登录界面、颁发令牌,并在每次 API 请求时验证令牌。迁移后,Descope 将接管所有这些职责。登录界面将变为嵌入应用的 Descope 组件。令牌验证将改由 Descope SDK 处理。原有的五个 Auth0 环境变量将替换为单个 Descope Project ID。
当前使用且需要保留的 Auth0 功能:[用通俗英语列出,每项用一个短语说明]。
根据分诊结果定制内容。
身份验证触点:代码分析结果
开头先说明范围数量(例如:“涵盖 4 个领域的 11 个文件”)。按领域分组,而不是按文件路径分组。 每组用一句话说明其作用和需要进行的更改。
会话处理(3 个文件) — 这些文件会读取并验证当前用户的登录状态。它们将改为使用 Descope 会话 SDK,而不是 Auth0。
| 文件 | 当前作用 | 更改内容 |
|---|---|---|
lib/auth.ts:34 | 返回包含 isAuthenticated、user、claims 的 Auth0 会话 | 改写为返回 Descope AuthenticationInfo;通过一个精简的适配层保留调用方所需的数据结构 |
middleware.ts:12 | 在整个应用中拦截未经身份验证的请求 | 更新为调用 Descope 会话验证;逻辑不变,仅更换 SDK 调用 |
登录 / 登出路由(2 个文件) — 这些路由处理基于 Auth0 重定向的登录流程。 Descope 会用嵌入式 UI 组件替代该流程;无需重定向。
| 文件 | 当前作用 | 更改内容 |
|---|---|---|
pages/api/auth/[...auth0].ts | 处理 OAuth 回调、登出和会话刷新的通用处理器 | 删除 — Descope 在客户端处理这些功能;无需服务器路由 |
涵盖所有功能分组。结尾写:“总计:N 个文件。预计代码更改工作量:N–N 小时。”
功能迁移:Auth0 → Descope
针对分类确认的每项 Auth0 功能,写一段简短说明:其目标、实现该目标的最佳 Descope 方案、两者的差异,以及所需操作。最佳方案可能是 Flow、Widget、SSO Setup Suite 或 Console 配置,而不一定是直接对应的 SDK 功能——应根据实际目的进行判断,而不只是看 API 表面。只有在确实需要编程控制时,才建议编写 SDK 代码。示例:
多租户(Auth0 Organizations → Descope Tenants) Auth0 Organizations 按公司对用户分组并限定其权限范围。Descope 也有相同的概念,称为 Tenants,迁移脚本会自动迁移这些数据。 主要差异在于租户成员资格在会话令牌中的表示方式——Auth0 使用扁平的
org_id字符串,而 Descope 使用包含各租户角色的嵌套tenants对象。任何读取req.auth.org_id的后端代码都需要改为读取token.tenants。这是一项可预期的机械性更改。 工作量:中等(1–2 小时)。 迁移脚本会处理数据;代码更改仅涉及读取令牌的逻辑。
仅包含已确认的功能。
代码运行前:必需的配置
Descope 的一些行为是在控制台中配置的,而不是在代码中配置。请列出应用正常运行前必须完成的所有设置,并以复选框的形式呈现,简单说明每项是什么、为什么需要,以及大致需要多长时间。分为“开始任何测试前必需”和“上线前必需”:
开始任何测试前必需:
- 创建 Descope 项目 — 耗时 2 分钟。生成一个项目 ID,用于替换应用环境变量中的所有 Auth0 凭据。
- 创建身份验证流程 — Descope 使用可视化的“流程”来定义登录体验(提供哪些方式,以及按什么顺序提供)。内置的
sign-up-or-in流程适用于大多数应用,开始使用时无需自定义。 - 配置用户个人资料令牌模板 — 默认情况下,Descope 会话令牌不包含用户的姓名、电子邮件或个人资料照片。需要配置此模板,以便应用显示用户个人资料信息。否则,登录后,任何显示用户姓名或电子邮件的界面都会为空。(约 10 分钟)
上线前必需:
- 创建角色:
admin、member(或代码库引用的其他角色)— 在控制台中创建 Descope 角色后,分配这些角色的代码才能正常运行。 - 配置社交登录提供商(Google、GitHub 等)— 需要在控制台中填写各个提供商的 OAuth 凭据。(每个提供商约 15 分钟)
- [ ](根据分析结果继续列出每项)
环境变量
差异表格,使用通俗易懂的语言说明每项移除和新增的变量:
| 移除 | 新增 | 原因 |
|---|---|---|
AUTH0_CLIENT_ID | — | Auth0 通过客户端 ID 识别应用。Descope 改用项目 ID,方式更简单,且同一项目中的所有应用共用该 ID。 |
AUTH0_CLIENT_SECRET | — | 不需要。Descope 的浏览器端流程不需要密钥。 |
AUTH0_ISSUER_BASE_URL | — | Auth0 租户 URL。改由项目 ID 取代。 |
AUTH0_AUDIENCE | — | Auth0 用它来限定 API 访问范围。如有需要,可通过 Descope 令牌模板实现相同功能。 |
SECRET | — | Auth0 SDK 用它加密服务器端会话。Descope 不使用服务器端会话。 |
| — | DESCOPE_PROJECT_ID | Descope 项目的唯一标识符,取代上述所有变量。 |
| — | NEXT_PUBLIC_DESCOPE_PROJECT_ID | 相同的值,公开给浏览器端的登录组件使用。 |
| — | DESCOPE_MANAGEMENT_KEY | 仅当应用在服务器端管理用户、角色或租户时才需要。 |
接着写:“总体变更:移除 5 个变量,新增 1–3 个变量。无需轮换 Auth0 端的密钥——这些凭据将不再使用。”
用户迁移(仅当需要迁移现有用户时)
先写策略说明,再列出步骤。以“需要在切换前将 X 个现有用户迁移到 Descope。”开头。说明:
- 计划:采用一次性迁移(在切换前迁移所有用户)还是分阶段迁移,以及原因
- 用户将遇到什么:他们是否需要重新登录?界面是否会有变化?
- 最大依赖项:如果密码迁移需要提交 Auth0 支持工单,请明确说明,并指出应立即提交——处理可能需要数天
最后附上简短的迁移步骤检查清单,便于项目经理跟踪进度:
- 提交 Auth0 支持工单,申请导出密码哈希(如适用)— 立即开始
- 从 Auth0 导出用户列表(如果超过 1,000 个用户)
- 对 Descope 开发项目运行迁移脚本试运行
- 检查试运行输出中的错误
- 先对暂存环境运行正式迁移,再对生产环境运行
权衡与注意事项
可能影响时间安排、用户体验或范围的事项。用通俗易懂的英文撰写,每项包含三个部分:是什么、忽略后会有什么问题以及该怎么做。 将每项格式化为带名称的提示框:
注意事项:配置令牌模板前,登录后不会显示用户资料 Descope 会话令牌默认不包含姓名、电子邮件或个人资料照片。迁移后,在 Descope 控制台设置好令牌模板之前,应用中任何显示用户信息的部分——个人资料页面、导航栏、问候文本——都会显示空值。这是一次性配置步骤,不需要修改代码。 操作: 在运行任何测试之前,在 Descope 控制台配置令牌模板。 预计耗时:10 分钟。
注意事项:迁移密码需要向 Auth0 提交支持请求 如果应用支持基于密码的登录,则必须从 Auth0 导出用户的密码哈希并导入 Descope。Auth0 只会通过支持工单提供这些数据,处理可能需要几天时间。 操作: 立即提交支持工单,同时开展开发工作。如果没有完成这一步,切换后使用密码登录的用户将需要重置密码。
仅包含适用的权衡与注意事项。
执行计划
以一句话开篇:各阶段按顺序执行;同一阶段内的步骤可以并行。 然后列出带标签的阶段,每个阶段都注明预计耗时:
阶段 1 — 控制台设置(约 30–45 分钟,无需编写代码) 任何有 Descope 控制台访问权限的团队成员都可以完成,并可与其他工作并行进行。
- 创建 Descope 项目,复制 Project ID
- 创建身份验证流程(先使用内置的
sign-up-or-in) - 配置用户资料令牌模板
- 创建角色:(列出实际发现的角色)
- 配置社交登录提供商:(列出实际发现的提供商)
阶段 2 — 代码更改(约 X–Y 小时,1 名工程师) 按列出的顺序处理文件。每组完成后运行编译检查。
- 删除
pages/api/auth/[...auth0].ts— 无需替代(5 分钟) - 更新
.env.example和 CI 配置中的环境变量(15 分钟) - 重写
lib/auth.ts会话助手(30 分钟) - 更新
_app.tsx— 将UserProvider替换为 DescopeAuthProvider(15 分钟) - 更新 8 个受保护路由文件,改用新的会话检查(45 分钟)
- 更新
lib/logout.ts— 执行两步登出(15 分钟) - 编译检查,并在继续之前修复所有类型错误
阶段 3 — 用户迁移(约 1–2 小时,包括试运行) 先在开发/预发布环境中运行。第 4 阶段通过之前,不要在生产环境中运行。
- (上文用户迁移部分中的步骤)
阶段 4 — 测试(约 30–45 分钟)
- 编译通过,零错误
- 服务器正常启动,启动时没有崩溃
- 未通过身份验证的路由会正确重定向到登录页
- 登录流程完成,用户资料数据显示正常(确认令牌模板工作正常)
- 登出会使会话失效
阶段 5 — 生产环境切换
- (根据其策略制定切换专属步骤——维护窗口、分阶段推出等)
预计工程总投入:N 名工程师合计 N–N 小时。 阻塞性依赖项:(列出关键路径上的事项——支持工单、控制台访问权限等)
写完 MIGRATION-PLAN.md 后,停止并告知用户:
已将
MIGRATION-PLAN.md写入你的工作目录。该文件梳理了发现的每个身份验证触点,列出了首次测试前需要在 Console 中完成的设置,并指出了可能影响时间安排的权衡与注意事项。开始更改之前,请先查看该文件。准备继续时,请告知我。
除非用户确认,否则不要继续第 3 部分。
第 3 部分:执行
按 MIGRATION-PLAN.md 第 8 节中的顺序执行计划。每个步骤都遵循下方的详细指导。
上下文连续性协议
不同轮次之间可能会丢失上下文。以下规则可确保迁移过程连贯。
步骤 3.0 — 在修改任何代码之前创建 MIGRATION-STATE.md。
根据下方模板,在工作目录中创建 MIGRATION-STATE.md。此文件是迁移状态的唯一事实来源;执行期间请及时更新。
# Migration State
_Last updated: [timestamp of last completed step]_
## Project Context
- Framework: [e.g., Next.js 14, Express + React]
- Language: [TypeScript / Python / Go]
- Package manager: [npm / yarn / pnpm / pip / etc.]
- Migration path: [Path A: OIDC compat / Path B: Full native]
- Migration goal: [Full cutover / Phased / Evaluating]
## Triage Answers
- Existing users: [Yes — N users / No — greenfield]
- Password migration needed: [Yes / No]
- Auth0 features in use: [comma-separated list]
- Multiple environments: [Yes: dev/staging/prod / No]
- Zero-downtime required: [Yes / No]
## Files Inventory
_All files that need to change. Update status after each step._
| File | Change | Status |
|---|---|---|
| `pages/api/auth/[...auth0].ts` | Delete | ⬜ Pending |
| `lib/auth.ts` | Rewrite session helper | ⬜ Pending |
| `middleware.ts` | Update session check | ⬜ Pending |
## Console Setup Checklist
- [ ] Descope project created — Project ID: (fill in when done)
- [ ] JWT template configured
- [ ] Roles created: (list roles)
- [ ] Social providers configured: (list providers)
## Decisions Log
_Non-obvious decisions made during migration — preserves rationale if context is lost._
_(none yet)_
## Current Phase
Phase 1 — Console Setup (not started)
## Next Action
Complete console setup per MIGRATION-PLAN.md before making any code changes.
## Blockers
_(none)_
规则 1 — 每轮开始前重新阅读。
每轮执行开始时,在编写任何代码或作出任何决定之前,重新阅读 MIGRATION-PLAN.md 和 MIGRATION-STATE.md。
规则 2 — 每次修改代码前确认上下文。
如果无法从对话中明确框架、迁移路径、分类问题的答案或下一步操作,请先重新阅读这两个文件,然后输出一行上下文信息:
Migration context: Next.js 14 · Path B · Phase 2, step 3/8 · Next: rewrite lib/auth.ts
如果无法准确填写此行,请先重新阅读这两个文件。
规则 3 — 每完成一步后立即更新 MIGRATION-STATE.md。
在文件清单中标记已完成的文件,更新“当前阶段”和“下一步操作”,并将任何不明显的决定追加到决策日志中。必须在进行下一步之前完成这些操作。
生成前协议(编写任何代码前应用)
在生成任何导入、封装类型或辅助函数前执行。跳过此步骤会导致代码虽然能编译,但在运行时失败。
1. 编写任何导入前,先确认 SDK 导出项。
如果 Docs MCP 可用,请使用 ask-question-about-descope 确认确切的方法名称、选项结构和返回类型,然后再编写任何 SDK 调用。这比阅读类型声明更快、更可靠。不要先写方法名,再附加“确认确切名称”之类的保留说明——直接确认即可。
如果 Docs MCP 不可用:请检查包的类型声明(node_modules/<pkg>/dist/types/ 或其 package.json 中的 types 字段),并确认确切的导出名称和签名。对于 Go,请运行 go doc。对于 Python,请检查 SDK 存根。
读取类型声明时,优先使用本地 node_modules/,而不是 GitHub。已安装的包反映了当前使用的确切版本。如果尚未安装 Descope 包,请先安装,再读取本地类型声明。只有在当前环境中无法安装该包时,才使用 GitHub。
这适用于你编写的每一次 SDK 调用,而不仅是首次导入。选项对象中的字段名(sendMail 与 sendEmail)、钩子的返回结构(useDescope() 直接返回 SDK,而不是 { sdk }),以及子路径导出(/client 与根路径)也经常不同。
1a. 重写任何模块后,使用 grep 查找是否仍有导入已移除包的情况。
grep -r "from '@/lib/auth0'\|from '@auth0/" --include="*.ts" --include="*.tsx" .
将剩余命中项添加到工作清单中。
2. 根据实际返回类型推导封装类型。 读取函数声明的返回类型,并据此构建封装。Auth0 的字段名、嵌套结构和标志位各不相同——不要根据它们推断。
3. 生成特定于框架的代码前,检查依赖版本。
对于 Next.js:next/headers 中的 cookies() 和 headers() 在 v14 中是同步的,在 v15 中则是异步的。请先读取 package.json(或 go.mod、requirements.txt)。
4. 将辅助函数改为异步时,立即更新所有调用方。
在 TypeScript 中,共享实用函数上的 async 会悄无声息地破坏未使用 await 的调用方。请 grep 查找已更改函数的所有调用位置,并在同一轮修改中更新它们。连锁影响可能涉及 10–20 个文件。
5. 写入 package.json 或运行 npm install 前,确认已发布的包版本。
不要复用 Auth0 的版本号,也不要依赖训练数据中的版本信息。编写任何安装命令前:
npm view @descope/node-sdk version
npm view @descope/nextjs-sdk version
如果 npm 不可用,请将版本保留为 "latest",并注明此情况。
步骤 1.5:Descope 项目设置与控制台配置
有几个步骤需要在 Descope 控制台中设置,无法通过代码完成。应用可以编译通过, 但运行时无法正常工作。
使用 AskUserQuestion 询问他们是否已有 Project ID 和可用的 Flow。如果有,跳过并
直接核对第 5–7 项——即使是已有项目,也很容易遗漏这些设置。
1. 创建项目并获取 Project ID
- 登录 console.descope.com
- Project ID 显示在左上角的项目选择器中,也可在 Project → Settings 下找到。它以
P开头(例如P2abc123...)。 - 对于 Next.js 客户端代码,它对应
NEXT_PUBLIC_DESCOPE_PROJECT_ID。对于所有服务端 SDK,它对应DESCOPE_PROJECT_ID。
2. 获取 Management Key(如有需要)
适用于:用户管理 API、角色/权限管理、租户操作、ReBAC (FGA)、Outbound Apps、SCIM 配置。如果应用需要在服务端管理用户或租户,就需要此密钥。
- 控制台 → Company → Management Keys → Generate Key
- 保存为
DESCOPE_MANAGEMENT_KEY。将其视为机密——切勿暴露在客户端。
3. 选择或创建 Flow
Flow 是身份验证 UI 流程。在 Web 组件中通过 Flow ID 引用它。
- 控制台 → Authentication → Flows
- 内置的 "sign-up-or-in" Flow 支持电子邮件/密码、OTP 和社交登录。 大多数迁移场景都可以使用它。
- 如需自定义:复制 "sign-up-or-in",重命名,然后在可视化构建器中编辑。
- 编辑时,Flow ID 会显示在 URL 中,也会显示在 Flow 列表中。
- 库中有 100 多个 Flow 模板——构建自定义 Flow 前,先查找是否已有合适的模板。参见
references/flows-and-widgets.md→ Flows。 - MFA:在 Flow 中添加 MFA 步骤,或将 MFA 嵌入为子流程。Descope 通过 Flow 管理 MFA 注册,而非通过 Management SDK——没有与 Auth0 Guardian 注册票据等效的功能。有关按类型提供的因子删除 SDK 支持,请参见
references/implementation-nuances.md→ MFA 部分。
4. 配置身份验证方式
- 控制台 → Authentication → 选择方式(Email OTP、Magic Link、Social、SSO 等)
- 对于社交提供商(Google、GitHub 等):在此配置 OAuth 凭据,然后将提供商步骤添加到 Flow 中。
- 对于企业 SSO(SAML/OIDC):控制台 → SSO → 按租户配置。有关正确的 SSO 回调和 ACS URL(社交 OAuth、SAML ACS,以及哪些地址不能使用),请参见
references/implementation-nuances.md→ Social login / SSO 部分。
5. 配置 JWT Template(几乎总是需要)
Auth0 默认会在令牌中包含 email、name 和 picture。Descope 不会。
- 控制台 → Authorization → JWT Templates → New Template
- 添加声明:
{"email": "{{user.email}}", "name": "{{user.name}}", "picture": "{{user.picture}}"} - 将模板应用到项目。如果不执行此步骤,迁移后任何读取
token.email的代码都会得到undefined。
6. 在控制台中创建角色(如果使用 RBAC)
Descope 通过名称而非 ID 引用角色。在分配角色的代码生效前,必须先在 控制台中手动创建角色。
- 控制台 → Authorization → RBAC → + Role
- 创建应用引用的每个角色(例如
admin、member)
7. 定义自定义属性(如果使用租户/用户元数据)
Auth0 Organization 的 metadata 和 User 的 app_metadata 映射到 Descope 的 customAttributes。
通过 SDK 设置这些属性前,请先在控制台架构中预先定义。
- 控制台 → Project → Custom Attributes
8. 环境变量摘要
| 变量 | 获取位置 | 用途 |
|---|---|---|
DESCOPE_PROJECT_ID | 控制台 → Project Settings | 所有服务端 SDK |
NEXT_PUBLIC_DESCOPE_PROJECT_ID | 与上述值相同 | Next.js AuthProvider(客户端) |
DESCOPE_MANAGEMENT_KEY | 控制台 → Company → Management Keys | Management SDK、Outbound Apps API |
9. 考虑使用管理 UI 的 Widgets
在迁移自定义个人资料页、用户管理页或角色分配 UI 之前,先确认 Descope Widget 是否
适用于此用例。请参阅 references/flows-and-widgets.md → Widgets。
完成控制台设置后: 更新 MIGRATION-STATE.md — 勾选控制台设置清单中的每个已完成
项目,在文件中记录 Project ID,并将 Next Action 设置为第一个代码更改步骤。
步骤 2:特定框架的迁移
编写任何代码之前,分两遍阅读 references/implementation-nuances.md:
- 通用见解(始终阅读)— 涵盖适用于所有迁移的架构、功能映射和常见问题,无论使用何种框架。
- 框架部分(使用文件的目录和
offset直接跳转)— 只阅读与用户技术栈匹配的部分:- Express.js →
## Express.js - Flask / Python、FastAPI →
## Flask / Python(FastAPI 说明位于「无即插即用中间件」子部分的通用见解中) - Next.js(App Router、独立部署)→
## Next.js (standalone)+## Next.js (B2B): Migration Bug Catalog - Next.js + 独立 Express API 服务 →
## Next.js (with separate Express API server) - Go →
## Go + Encore - LangChain / LangGraph / Vercel AI 搭配 FGA 或 Token Vault →
## Agentic AI Stacks
- Express.js →
在文件中添加新框架时,也将其添加到此列表中。
Express.js
- 移除
express-openid-connect;添加@descope/node-sdk+cookie-parser - 将
app.use(auth(config))替换为约 20 行的自定义中间件,用于读取DScookie 并调用descopeClient.validateSession() - 添加
/login路由,渲染<descope-wc>Web 组件(EJS、纯 HTML 等) - 登出:调用
descopeClient.logout(refreshToken)+ 清除DS/DSRcookies
重要注意事项:
express-openid-connect在内部处理了 CSRF 和 cookie 解析。你需要显式添加cookie-parser。req.oidc.user→req.user(在validateSession()验证 JWT 声明后设置)requiresAuth()是 3 行自定义代码,不是 SDK 导入项。
Flask / Python
- 移除
authlib;添加descopePython SDK - 完全移除
/callback路由 — 无需代码交换 /login渲染 Descope Web 组件,而不是调用authorize_redirect()- 登出:调用
descope_client.logout(refresh_token)+ 删除 cookies - 移除 Flask
session;状态存储在DS/DSRcookies 中
重要注意事项:
authlib将access_token、id_token、userinfo存储在 Flask 服务端 session 中。 Descope 不使用 Flask sessions。移除APP_SECRET_KEY和session导入。validate_session()返回一个 JWT 声明字典。默认不包含个人资料字段 — 请先配置 JWT Template。
Next.js
@auth0/nextjs-auth0→@descope/nextjs-sdk+@descope/node-sdkUserProvider→AuthProvider(接受projectId属性;必须使用NEXT_PUBLIC_前缀)useUser()→useSession()+useUser()(Descope 将会话状态与用户数据分开处理)- 移除
pages/api/auth/[...auth0].tsx全捕获路由——不进行服务端 OIDC 处理 - 添加
/login页面,使用<Descope>组件渲染sign-up-or-in流程;始终绑定onSuccess——该组件不会自动重定向(参见references/implementation-nuances.md→ Next.js 章节) withPageAuthRequired→ 手动检查useSession()+ 重定向withApiAuthRequired→ 在处理程序顶部调用session(),并手动返回 401- 登出:通过
useDescope()钩子调用sdk.logout()(不要链接到/api/auth/logout)
客户端与服务端会话访问——常见错误来源:
@descope/nextjs-sdk/server中的session()——仅用于服务端组件、服务端操作、API 路由@descope/nextjs-sdk/client中的useSession()+useUser()——用于 React 客户端组件useSession()返回{ isAuthenticated, sessionToken, ... }useUser()返回当前会话中的用户对象
- 在客户端组件中使用
session()虽然可以编译,但会在运行时抛出异常(因为它会尝试在浏览器上下文中读取 Cookie)。完成任何 Next.js 迁移前,都要扫描这种用法。
服务端会话——准确的 SDK API(生成前请验证):
@descope/nextjs-sdk/server 入口恰好导出:
session(config?)——在服务端组件或服务端操作中,从请求标头/Cookie 读取会话。不接受req参数。返回Promise<AuthenticationInfo | undefined>。getSession(req, config?)——从显式传入的NextApiRequest读取会话。仅用于 API 路由。authMiddleware(options)——Next.js 中间件工厂。
不存在 getServerSession。这个名称看起来似乎合理,但并未导出。编写任何导入语句前,打开 node_modules/@descope/nextjs-sdk/dist/types/server/index.d.ts 并确认导出列表。
会话返回类型是 AuthenticationInfo,而不是 Auth0 风格的会话对象:
session() 返回 @descope/node-sdk 中的 AuthenticationInfo | undefined:
interface AuthenticationInfo {
jwt: string // raw session JWT
token: Token // decoded claims: { sub?, exp?, iss?, [claim: string]: unknown }
cookies?: string[]
}
没有 isAuthenticated,没有 claims 字段,也没有 user 包装对象。请改为编写一个适配器函数:
import { session as sdkSession } from "@descope/nextjs-sdk/server"
export async function getDescopeSession() {
const authInfo = await sdkSession()
if (!authInfo) return null
return { isAuthenticated: true as const, jwt: authInfo.jwt, token: authInfo.token }
}
然后使用此本地文件中的 getDescopeSession() 生成所有服务端组件,不要直接从 SDK 调用。
对于使用独立 API 服务(Express)的应用:
- 移除
express-jwt+jwks-rsa;替换为descopeClient.validateSession() - 将
DSCookie 作为Authorization: Bearer <DS>从 Next.js 转发到 API - 不需要单独的访问令牌——会话令牌就是承载令牌
FastAPI / Python
- 移除
auth0-fastapi(AuthConfig、自动挂载的/api/auth/*路由、require_session) - 添加自定义
TokenVerifier类:读取Authorization标头,根据 Descope JWKS 验证令牌,并将声明作为 FastAPISecurity()依赖附加 - 不会自动挂载路由;没有会话存储
路径 A:OIDC 兼容(风险较低,渐进式迁移)
Descope 提供标准 OIDC 端点。如果应用使用 OIDC 客户端库
(express-openid-connect、go-oidc、authlib、@auth0/nextjs-auth0 v4 等),只需
进行少量代码更改,即可将其指向 Descope 的 OIDC 颁发者,而非 Auth0:
| 端点 | Auth0 | Descope |
|---|---|---|
| 颁发者 | https://YOUR_DOMAIN.auth0.com | https://api.descope.com |
| 授权 | https://YOUR_DOMAIN.auth0.com/authorize | https://api.descope.com/oauth2/v1/authorize |
| 令牌 | https://YOUR_DOMAIN.auth0.com/oauth/token | https://api.descope.com/oauth2/v1/token |
| UserInfo | https://YOUR_DOMAIN.auth0.com/userinfo | https://api.descope.com/oauth2/v1/userinfo |
| JWKS | https://YOUR_DOMAIN.auth0.com/.well-known/jwks.json | https://api.descope.com/__ProjectID__/.well-known/jwks.json |
@auth0/nextjs-auth0 v4(Auth0Client)的 Descope 配置:
new Auth0Client({
domain: `https://api.descope.com/${DESCOPE_PROJECT_ID}`,
clientId: DESCOPE_OIDC_CLIENT_ID, // from Descope Console → Applications → OIDC App
clientSecret: DESCOPE_OIDC_CLIENT_SECRET,
logoutStrategy: "oidc", // prevents calling Auth0's /v2/logout
secret: SESSION_ENCRYPTION_SECRET, // still needed for server-side session encryption
})
通过 OIDC 迁移到 Descope 时,无法沿用的 Auth0 专用参数:
screen_hint: "signup"— Auth0 专用参数,Descope 会忽略organization: orgId— Descope 没有与 Auth0 组织级登录对应的 OIDC 功能appClient.updateSession()— 没有对应功能;登录后会话为只读
适用场景: 希望先切换 IdP,之后再重构为 Descope 原生 SDK 的团队。 可保留现有的 OIDC 客户端代码。
注意事项: 声明形状可能不同,令牌有效期也可能不同;无论选择哪条路径,都必须在 Descope Flows 中重建 Auth0 Actions。
适用于使用 Auth0 Organizations 的 B2B 应用: 路径 A 大致可保留 20% 的工作 (中间件、
getSession()、会话路由);其余 80%(管理 SDK、组织级登录、 注册流程、声明映射)无论如何都需要完整迁移。对于 B2B 工作负载,路径 A 的 节省有限——估算工作量时请考虑这一点。
Go
- 移除
go-oidc+golang.org/x/oauth2;添加descope/go-sdk - 移除登录/回调/登出后端端点(约 150 行)——只保留令牌验证
- 会话验证:
descopeClient.Auth.ValidateSessionWithToken(ctx, token)返回(bool, *descope.Token, error)。Token.Claims的类型为map[string]interface{} sub声明直接映射到认证处理程序的用户 ID- 认证配置:ClientID + ClientSecret + Domain + RedirectURL → 仅需 ProjectID
完成框架代码更改后: 更新 MIGRATION-STATE.md——在文件清单中将每个
已修改文件标记为 Done,更新当前阶段和下一步操作,并记录任何不明显的决策(保留的适配器类型、异步级联范围等)。
步骤 2.5:非代码文件更新
更新源文件后,扫描非代码文件中的 Auth0 引用。
.env.example / .env.template / .env.sample
# REMOVE
AUTH0_CLIENT_ID=
AUTH0_CLIENT_SECRET=
AUTH0_ISSUER_BASE_URL=
AUTH0_AUDIENCE=
AUTH0_BASE_URL=
SECRET=
# ADD
DESCOPE_PROJECT_ID= # Console → Project Settings
NEXT_PUBLIC_DESCOPE_PROJECT_ID= # Next.js only — same value as above
DESCOPE_MANAGEMENT_KEY= # Console → Company → Management Keys (only if using management SDK)
运行 grep -r "AUTH0" 查找所有环境变量引用——包括 .env.example、Docker、CI 和 shell 脚本。
README / 文档
在所有 .md 文件中搜索 Auth0 引用。至少更新以下内容:
- 设置部分——将“创建 Auth0 应用”的说明替换为 Descope Console 设置步骤
- 环境变量部分——反映精简后的环境变量集
- 运行说明——将 Auth0 租户步骤替换为 Descope Console 步骤
- 认证流程图或说明——更新为反映 Descope 基于 Cookie 的方式
Docker / CI 文件
检查 Dockerfile、docker-compose.yml、.github/workflows/ 和任何 CI 配置中是否声明了
AUTH0_* 环境变量。将其更新为 DESCOPE_*。
设置 / 引导脚本
Auth0 CLI 命令(auth0 tenants patch、auth0 actions create/deploy、auth0 roles create 等)没有对应的 Descope CLI 命令。如果迁移中包含设置或种子脚本(例如,scripts/bootstrap.mjs、scripts/seed.ts),请将其拆分为两部分:
- 控制台设置(无法通过脚本完成):Flows、电子邮件模板、MFA 配置、品牌 / 样式 — 在 Descope Console 中配置这些内容。将其作为
MIGRATION-PLAN.md中的 Phase 1 检查清单。 - SDK 自动化(可以通过脚本完成):角色创建(
management.role.create())、租户创建、访问密钥配置。使用 Descope Management SDK 将其保留为 Node.js/Python 脚本。
需要重新评估由脚本部署的 Auth0 Actions:每个 Action 的逻辑都应映射到 Console 中的 Flow 步骤、Scriptlet 或 Connector,而不是代码部署。如果任何 Action 的意图不明确,请使用 AskUserQuestion。
完成非代码文件更新后: 更新 MIGRATION-STATE.md — 在 Files Inventory 中将环境文件、
README 和 CI 配置标记为已完成,并推进 Next Action。
第 3 步:功能迁移映射
Auth0 Actions / Rules → Descope Flows + JWT 模板
| Auth0 模式 | Descope 对应项 |
|---|---|
| Token 中的自定义声明 | JWT Templates |
| 身份验证期间的自定义逻辑 | Descope Flows |
| 登录后 Webhook | Flows → Connectors |
| 登录时分配角色 | Flow 操作 → RBAC 角色分配步骤 |
社交登录 → Descope 社交身份验证
- 在 Descope Console 的 Authentication → Social 下配置提供商
- 将其添加到 Flow(无需更改代码)
- Descope Web 组件会自动呈现已配置的提供商
MFA 注册 → Descope Flows
迁移 MFA 注册前: 许多 Auth0 应用都有单独的 MFA 注册页面,因为 Auth0 Guardian 通过服务器生成的注册票据 URL 工作。这种模式在 Descope 中没有对应方案,而且单独的页面在 Descope 中很少是合适的做法。
Descope 的做法:直接在注册 / 登录 Flow 中添加 MFA 步骤 — 在身份验证流程中内联完成注册。也可以将 MFA 嵌入为子流程(由条件触发:用户是管理员、风险评分超过阈值等)。或者使用 step-up Flow 模板来保护敏感操作。
操作: 编写任何 MFA 注册代码前,使用 AskUserQuestion 确认能否将 MFA 集成到主登录 Flow 中。请参阅 references/flows-and-widgets.md → MFA 注册部分。
RBAC:Auth0 角色 / 权限 → Descope RBAC
| Auth0 | Descope |
|---|---|
req.auth.permissions.includes('read:messages') | token.permissions.includes('read:messages') |
| Actions 中通过命名空间添加角色声明 | JWT 中的 roles 数组(内置) |
| 用于 Management API 的 M2M token | 管理 SDK 使用的 DESCOPE_MANAGEMENT_KEY |
SDK:descopeClient.management.role.create(name, description, permissionNames, tenantId)
多租户:Auth0 Organizations → Descope Tenants
- Auth0
org_id(扁平字符串)→ Descopetenants(嵌套对象:{ tenantId: { roles, permissions } }) - Auth0 组织范围的登录 → Descope 根据电子邮件域名或租户专属 URL 进行路由
- 在 Descope 中,用户属于项目级别;用户与租户关联,而非按租户创建
企业 SSO → Descope 租户 SSO
首选方案 — SSO Setup Suite: 在迁移 Management SDK 的 SSO 调用之前,先确认 SSO Setup Suite 是否可以免去这部分代码。SSO Setup Suite 是一个无需编写代码的 Console 向导,可引导租户管理员逐个租户配置 SAML/OIDC,并提供针对特定 IdP(Okta、Microsoft Entra ID(原 Azure AD)、Google Workspace 等)的分步说明——新租户接入 SSO 无需工程团队参与。
使用 AskUserQuestion 询问:此应用是否需要以编程方式配置 SSO(CI/CD 预配、通过 API 驱动租户接入),还是由租户管理员通过设置页面自行配置 SSO?如果是后者,SSO Setup Suite + Tenant Profile Widget 或许可以完全免去 sso.configureSAMLByTenant() / configureOIDCByTenant() 调用。
参见 references/flows-and-widgets.md → SSO Setup Suite。
SDK 方案(需要以编程方式配置 SSO 时):
| Auth0 | Descope |
|---|---|
connections.create({ strategy: "samlp" }) | management.sso.configureSAMLByTenant(tenantId, settings) |
connections.create({ strategy: "oidc" }) | management.sso.configureOIDCByTenant(tenantId, settings) |
| 每个组织的 SAML 连接 | 每个租户的 SSO(Console → SSO 或 Management SDK) |
Auth0 FGA(OpenFGA)→ Descope ReBAC
Schema 转换示例:
# Auth0/OpenFGA
type doc
relations
define owner: [user]
define viewer: [user, user:*]
define can_view: owner or viewer
# Descope ReBAC DSL
type doc
relation owner: user
relation viewer: user
permission can_view: owner or viewer
API 形式差异:
- OpenFGA:
{ user, relation, object }元组 - Descope:
{ target, targetType, relation, resource, resourceType }— 明确的类型化字段
| 操作 | Auth0 FGA | Descope ReBAC |
|---|---|---|
| 写入关系 | fgaClient.write({ writes: [...] }) | descopeClient.management.fga.createRelations([...]) |
| 检查 | fgaClient.check({ user, relation, object }) | descopeClient.management.fga.check([...]) |
| 列出对象 | fgaClient.listObjects(...) | descopeClient.management.authz.whatCanTargetAccessWithRelation(...) |
注意:@auth0/ai-langchain 中的 FGARetriever 没有对应的 Descope 实现。请构建自定义检索器,为每个候选文档调用 descopeClient.management.fga.check()。
Token Vault / Connected Accounts → Descope Outbound Apps
用户通过客户端上的 sdk.outbound.connect(appId, { redirectURL, scopes }) 连接账户。
在服务端获取已存储的令牌:
POST https://api.descope.com/v1/mgmt/outbound/app/user/token
Authorization: Bearer {projectId}:{managementKey}
Body: { "appId": "google-calendar", "userId": "U2abc...", "scopes": [...] }
没有 AI 框架封装(@auth0/ai 中的 withTokenVault() 没有对应实现)。
请构建自定义工具封装,直接调用 Outbound Apps API。
CIBA / 异步授权 → 需要自定义实现
Descope 没有 CIBA 对应实现。建议采用以下方案:
- Agent 在你的数据库中创建一条待审批记录
- 前端轮询该记录(或使用 WebSocket)
- 用户通过 Descope Flow 或自定义 UI 批准
- Agent 收到批准信号后继续执行
这是迁移中复杂度最高的项目。
M2M / 客户端凭据 → Descope Access Keys
Auth0 M2M 应用使用客户端凭据授权。Descope 的对应功能是
Access Keys——在
Console → Access Keys 中创建一个,通过 descopeClient.auth.exchangeAccessKey() 将其换取为 JWT,
并以与用户令牌相同的方式验证生成的令牌。
用户迁移 → Descope 迁移脚本
Descope 提供了一个 Python CLI 工具 — descope/descope-migration,可在一次运行中批量导入用户、角色、权限和 Auth0 组织(→ Descope 租户)。
两种导入模式:
- Auth0 API — 用户少于 1,000 时使用
- JSON 导出 — 用户达到 1,000 或以上时使用;通过 Auth0 的 User Import/Export 扩展导出
设置:
git clone [email protected]:descope/descope-migration.git
cd descope-migration
python3 -m venv venv && source venv/bin/activate
pip3 install -r requirements.txt
cp .env.example .env
必需的 .env 变量:
| 变量 | 获取位置 |
|---|---|
AUTH0_TOKEN | Auth0 Management API → token explorer(24 小时令牌) |
AUTH0_TENANT_ID | 你的 Auth0 控制面板 URL |
DESCOPE_PROJECT_ID | Descope Console → Project Settings |
DESCOPE_MANAGEMENT_KEY | Descope Console → Company → Management Keys |
务必先进行试运行:
python3 src/main.py auth0 --dry-run
python3 src/main.py auth0 --dry-run --from-json ./export.json --with-passwords ./password_hashes.json
迁移内容: 用户、角色、权限、Auth0 组织 → Descope 租户。
自动创建的自定义属性:
connection(文本)— 每位用户的 Auth0 连接类型freshlyMigrated(布尔值)— 导入时设为true;在 Flow 条件中使用此属性,为新迁移的用户提供特殊的首次登录体验,完成后再将其设为false
会话迁移(测试版): 若要实现零中断切换,可将活跃的 Auth0 会话 交换为 Descope 令牌,而无需重新进行身份验证。要求用户已存在于 Descope 中(先导入)。请参阅会话迁移文档。
大型用户群(10,000+)— 通过 Auth0 Action 即时迁移: 对于用户数量庞大的情况,批量导出/导入可能造成中断。Auth0 支持创建一个 Action,在切换窗口期间每次用户登录时将用户数据转发到 Descope — 用户可以逐步即时迁移,无需强制重新登录。此方案需要与 Descope Customer Success 团队协调。如果用户希望实现零中断切换,请标记此项。
电子邮件模板 → Descope Messaging Templates
Auth0 电子邮件模板对应 Descope Messaging Templates, 可在 Console 中按身份验证方式进行配置。
日志流 → Descope Audit Webhook
Auth0 Log Streams 对应 Descope 的 Audit Webhook Connector。 请在切换前完成设置,以避免事件日志出现缺失。
自定义域名
将 CNAME auth.example.com 指向 cname.descope.com,在 Console 中验证,然后将 baseUrl 传递给
Descope SDK。
攻击防护 → Descope Flow Security
Auth0 Attack Protection 对应使用安全连接器的 Descope Flow 步骤:Arkose Bot Manager、 Google reCAPTCHA、Fingerprint、Have I Been Pwned、AbuseIPDB。这些功能可组合使用(向 Flow 添加 检测步骤),而不是通过开关控制 — 默认未配置。
完成功能迁移后: 更新 MIGRATION-STATE.md — 记录已迁移的功能,标记任何已延期或需要后续处理的功能,并将 Next Action 推进到测试阶段。
第 4 步:关键注意事项(务必涵盖)
JWT 声明并不相同
Descope 会话 JWT 默认包含 sub、amr、drn、tenants、roles、permissions 和 dct。它们默认不包含 email、name 或 picture。Auth0 ID 令牌默认包含这些字段。
dct(Descope Current Tenant)是一个保存当前租户 ID 的普通字符串 — 相当于 Auth0 的 org_id。对于用户始终处于单个租户上下文中的应用,读取 token.dct 比遍历 token.tenants 更简单。需要按租户获取角色或权限时,使用 token.tenants(它是一个键控对象:{ [tenantId]: { roles, permissions } });只需要租户 ID 时,使用 token.dct。
需要执行的操作: 在 Descope Console 中配置 JWT Template,将 email、
name 以及应用从令牌中读取的其他个人资料字段添加进去。
受众验证为可选项
Descope 会话令牌默认不包含 aud 声明。使用 AUTH0_AUDIENCE 进行 API 访问控制的应用必须:
- 在 JWT Templates 中配置自定义
aud声明 - 在后端调用
validateSession()时传入audience
登出分为两个步骤
- 调用
descopeClient.logout(refreshToken)使服务器端会话失效 - 清除
DS和DSRCookie
跳过任一步骤都会导致状态异常。
服务器端的个人资料更新不会立即反映在会话令牌中
Auth0 的 appClient.updateSession() 没有直接对应的 Descope 服务器端方法。通过 Management SDK 修改个人资料不会更新浏览器中已有的 JWT。可选方案有四种:
- 等待自动刷新(默认约 5 分钟)——无需编写代码;对大多数应用来说可以接受。
- 在客户端调用
useDescope().refresh()——立即触发令牌刷新。要求个人资料表单是包含useDescope()Hook 的客户端组件。完整代码模式见references/implementation-nuances.md→ 会话刷新部分。 - Update JWT 端点(
POST /v1/mgmt/user/jwt/update)——服务器端方法;更新特定用户已存储 JWT 中的自定义声明。使用前请对照 Descope 文档核实当前行为——此方法更新的是已存储的声明,而非实时会话令牌。 - User Profile Widget——如果应用正在构建个人资料编辑页面,Widget 会自动处理个人资料更新和会话刷新,无需自定义代码。参见
references/flows-and-widgets.md→ Widgets。
会话变更事件监听器: 与其主动调用 refresh(),不如使用 Descope 客户端 SDK 提供的认证状态变更事件,以便在各个组件中响应会话更新。参见 docs.descope.com/client-sdk/auth-helpers#handling-authentication-state-changes。
Cookie 名称可配置(也可能发生冲突)
默认值:DS(会话 JWT)、DSR(刷新 JWT)。在同一根域名下运行多个 Descope 项目时,可在 Descope Console 中 Flow 的 End 操作下配置自定义名称。
只有一个令牌,而不是两个
Auth0 会分别签发 ID 令牌和访问令牌。Descope 只有一个令牌:会话 JWT(DS Cookie)。将其作为 Authorization: Bearer <DS> 转发给 API 服务器。
没有开箱即用的中间件
Descope 没有与 express-openid-connect 等效的程序包。中间件需要约 20 行自定义代码。
Next.js 15 中的 cookies() 和 headers() 是异步的
在 Next.js 15+ 中,next/headers 的 cookies() 和 headers() 会返回一个 Promise。在生成任何读取 Cookie 的服务器端辅助函数之前:
- 检查项目的
package.json,确认 Next.js 版本。 - 如果版本 ≥ 15:编写
await cookies(),并将其所在函数标记为async。 - 沿调用链向上追踪——将读取 Cookie 的辅助函数改为异步,会连带影响所有调用者。
异步级联:完成前追踪所有调用者
共享工具变为异步后,TypeScript 允许对非 Promise 使用 await 而不报错——因此,忘记使用 await 的调用者会悄悄返回一个 Promise 对象。每当将某个工具改为异步时,务必使用 grep 查找所有调用位置,并在同一轮中更新。
环境变量精简
Auth0:CLIENT_ID、CLIENT_SECRET、ISSUER_BASE_URL、SECRET、AUTH0_AUDIENCE(至少 5 个)。
Descope:仅需 DESCOPE_PROJECT_ID(管理操作还需 DESCOPE_MANAGEMENT_KEY)。
步骤 5:自动化测试
运行应用并验证其正常工作——不要只交付一份检查清单。
阶段 0:最终清理过期导入(阻断性)
grep -r "@auth0\|auth0\|express-openid-connect\|nextjs-auth0" \
--include="*.ts" --include="*.tsx" --include="*.js" --include="*.py" --include="*.go" \
--exclude-dir=node_modules --exclude-dir=.next --exclude-dir=dist \
.
如果有任何结果,请停止并先修复,再继续。
阶段 1:安装、编译并启动
npm install # or: pip install -r requirements.txt / go mod tidy
npx tsc --noEmit # TypeScript
go build ./... # Go
mvn compile -q # Java/Maven
./gradlew compileJava compileKotlin # Java/Gradle
dotnet build # .NET
编译未以零错误退出前,不要继续。
如果编译失败,请根据错误消息进行诊断:
Cannot find module '@auth0/...'→ 导入已过时;重新运行阶段 0Property 'X' does not exist on type 'AuthenticationInfo'→ 包装器是基于 Auth0 的结构构建的;重新推导'await' expression is not allowed in synchronous contexts→ 异步级联存在缺口- 会话字段上出现
Object is possibly 'undefined'→ 添加空值检查或提前返回
npm run dev # or: python main.py / go run . / flask run / etc.
阶段 2:运行现有测试
npm test # or: pytest / go test ./... / etc.
与身份验证相关的测试失败通常意味着:某个模拟或测试夹具仍使用 Auth0 的结构,或者某项测试验证了现在缺失的 JWT 声明(例如,没有 JWT 模板时的 email)。
阶段 3:对运行中的应用进行冒烟测试
# Root path
curl -s -o /dev/null -w "%{http_code}" http://localhost:<port>/
# Unauthenticated protected route (expect 302 or 401)
curl -s -o /dev/null -w "%{http_code}" http://localhost:<port>/dashboard
# Login page loads Descope component
curl -s http://localhost:<port>/login | grep -i "descope"
# Invalid token → 401
curl -s -H "Cookie: DS=invalid_token" http://localhost:<port>/api/me
阶段 4:验证 JWT 声明(如果已配置 JWT 模板)
echo "<DS_cookie_value>" | cut -d'.' -f2 | base64 -d 2>/dev/null | python3 -m json.tool
检查 email、name 和其他预期声明是否存在。
阶段 5:报告结果
## Test Results
**Server startup:** ✅ Started successfully on port 3000
**Existing tests:** ✅ 12 passed / ❌ 2 failed (list failures)
**Unauthenticated /dashboard:** ✅ 302 → /login
**Unauthenticated /api/protected:** ✅ 401
**Login page loads Descope component:** ✅
**JWT claims (email, name):** ✅ Present / ❌ Missing — JWT Template not yet configured
**Blockers before going live:**
- [ ] (list anything that failed or needs manual action)
只有满足以下所有条件后,才能继续执行步骤 6:
- 阶段 0 的 grep 检查未返回任何 Auth0 引用
- 阶段 1 编译通过,且没有错误
- 阶段 1 服务已启动并持续运行
- 阶段 3 根路径返回 2xx 或 3xx(而非 5xx)
- 阶段 3 受保护路由返回 302 或 401(而非 500)
步骤 6:迁移摘要(必需)
每次迁移都必须生成 MIGRATION-SUMMARY.md,说明已完成的工作、仍需进行的手动设置,以及上线前需要了解的行为差异。
MIGRATION-SUMMARY.md
-
迁移内容 — 使用表格列出每个 Auth0 概念及其对应的 Descope 替代方案
-
行为差异和待解决问题 — 使用编号列表列出 Auth0 和 Descope 实现之间的重要差异。每项须说明:Auth0 的行为、Descope 的行为、所需操作。
-
部署前检查清单 — 使用可执行的复选框项目,列出迁移后的应用运行前必须完成的所有事项。醒目列出所有 Console 设置任务——这些事项最容易被遗漏,因为即使不完成它们,代码也能编译通过。
步骤 7:输出格式
使用 Markdown 编写编号迁移指南,并根据用户的技术栈调整范围。使用代码片段和直接文档链接。始终包含 MIGRATION-SUMMARY.md 交付物(步骤 6)。
对于复杂迁移(FGA、CIBA、AI 工具),明确标注高工作量项目,并估算复杂度(低/中/高),以便用户进行规划。
参考文件
references/implementation-nuances.md— 多种框架的已验证迁移模式、代码级差异和边缘情况。- Descope 文档:https://docs.descope.com
- Auth0 迁移指南:https://docs.descope.com/migrate/auth0
- 用户导入(自定义):https://docs.descope.com/migrate/custom
- Descope OIDC 端点:https://docs.descope.com/getting-started/oidc-endpoints
- Descope 流程:https://docs.descope.com/flows
- JWT 模板:https://docs.descope.com/management/jwt-templates
- Access Keys(M2M):https://docs.descope.com/management/m2m-access-keys
- 消息模板:https://docs.descope.com/management/messaging-templates
- 审计 Webhook:https://docs.descope.com/connectors/connector-configuration-guides/network/audit-webhook
- 自定义域名:https://docs.descope.com/how-to-deploy-to-production/custom-domain
- ReBAC:https://docs.descope.com/authorization/rebac
- 出站应用:https://docs.descope.com/identity-federation/outbound-apps
按语言查看会话验证
- Node.js:https://docs.descope.com/getting-started/nodejs#implement-session-validation
- Python:https://docs.descope.com/getting-started/python#implement-session-validation
- Go:https://docs.descope.com/getting-started/golang#implement-session-validation
- Ruby:https://docs.descope.com/getting-started/ruby#implement-session-validation
- Java / Kotlin:https://docs.descope.com/getting-started/java#implement-session-validation
- .NET / C#:https://docs.descope.com/getting-started/dotnet#implement-session-validation
- Next.js:https://docs.descope.com/getting-started/nextjs#implement-session-validation
- React:https://docs.descope.com/getting-started/react#implement-session-validation
- Angular:https://docs.descope.com/getting-started/angular#implement-session-validation
- Vue:https://docs.descope.com/getting-started/vue#implement-session-validation
- Swift / iOS:https://docs.descope.com/getting-started/swift#implement-session-validation
- Kotlin / Android:https://docs.descope.com/getting-started/android#implement-session-validation
- Flutter:https://docs.descope.com/getting-started/flutter#implement-session-validation
SDK(GitHub)
- Node SDK:https://github.com/descope/node-sdk
- Python SDK:https://github.com/descope/python-sdk
- Go SDK:https://github.com/descope/go-sdk
- Ruby SDK:https://github.com/descope/descope-ruby-sdk
- Java SDK:https://github.com/descope/descope-java
- .NET SDK:https://github.com/descope/descope-dotnet
- Swift SDK:https://github.com/descope/swift-sdk
- Kotlin SDK:https://github.com/descope/descope-kotlin
- Flutter SDK:https://github.com/descope/descope-flutter
- JS/TS 单体仓库(React、Angular、Vue、Next.js、Web Component、Web JS):https://github.com/descope/descope-js