mcpField
A
auth0-to-descope

auth0-to-descope

github.com/descope安全1838 次安装1 天前更新
代码仓库

关于 auth0-to-descope

面向工程师的 Auth0 到 Descope 认证迁移技能。它将 MCP 检查、代码分析和可审阅的迁移计划与实际执行分开,只有计划获批后才开始修改代码。

主要功能

  1. 01检查 Descope Docs MCP 是否可用
  2. 02收集迁移需求
  3. 03定位认证代码触点
  4. 04生成供审阅的 MIGRATION-PLAN.md
  5. 05仅在计划获批后执行

适用场景

  1. 01规划从 Auth0 迁移到 Descope
  2. 02在实施前审阅认证变更
  3. 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 的自助式迁移。分为三个部分:

  1. MCP 检查 — 确认 Descope Docs MCP 是否可用;如果不可用,则建议安装
  2. 迁移计划 — 通过分类问题收集背景信息,分析代码库中的身份验证触点,并生成便于用户阅读的 MIGRATION-PLAN.md 供其审核
  3. 执行 — 如果用户确认要继续,则执行计划

不要将这些部分合并,也不要跳过步骤。开始更改代码前,必须先审核计划。

主要参考资料(均位于此技能的目录中):

  • 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 部分包含两个子步骤:

  1. 分类 — 提出了解迁移范围所需的问题(迁移相关问题应在此处提出,因为答案会影响计划)
  2. 代码库分析 + 计划文件 — 扫描项目,生成 MIGRATION-PLAN.md,然后暂停等待审核
步骤 0:分流(阻塞性——需要使用 AskUserQuestion)

使用 AskUserQuestion 工具收集以下信息。不要根据记忆、之前的对话或假设推断答案——即使你认为自己知道答案也不行。 迁移路径会根据这些答案而有所不同;弄错会浪费用户的时间,并给出错误的指导。

在用户回答之前,不要继续执行步骤 0.5。

第一次调用 AskUserQuestion(最多 4 个问题):

  1. 后端语言 / 框架——根据对话中的任何线索,提供最可能的选项(例如 Express、Next.js、Flask/FastAPI、Go)。用户始终可以选择“其他”。
  2. 迁移目标——完全切换、增量 / 分阶段迁移,还是仅进行评估。
  3. 现有用户群体——他们是在迁移一款已有 Auth0 活跃用户的应用,还是从头开始?这决定是否需要规划用户迁移(密码哈希、批量导入、分阶段切换还是一次性切换、切换时强制重新登录)。
  4. 偏好的迁移方式——他们希望直接嵌入 Descope Flows/Widgets(完全原生迁移),还是保留现有的 OIDC 客户端库,并将其指向 Descope 的 OIDC 端点(OIDC 兼容层)?注意:B2B 功能(Organizations/SSO/SCIM 管理)没有 OIDC 层的对应方案,无论采用哪种路径都需要调用原生 SDK。

第二次调用 AskUserQuestion——Auth0 功能使用情况(使用 multiSelect: true):

  1. 目前在使用哪些 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_IDDescope 项目的唯一标识符,取代上述所有变量。
—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 替换为 Descope AuthProvider(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 KeysManagement 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:

  1. 通用见解(始终阅读)— 涵盖适用于所有迁移的架构、功能映射和常见问题,无论使用何种框架。
  2. 框架部分(使用文件的目录和 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-openid-connect;添加 @descope/node-sdk + cookie-parser
  • 将 app.use(auth(config)) 替换为约 20 行的自定义中间件,用于读取 DS cookie 并调用 descopeClient.validateSession()
  • 添加 /login 路由,渲染 <descope-wc> Web 组件(EJS、纯 HTML 等)
  • 登出:调用 descopeClient.logout(refreshToken) + 清除 DS/DSR cookies

重要注意事项:

  • express-openid-connect 在内部处理了 CSRF 和 cookie 解析。你需要显式添加 cookie-parser。
  • req.oidc.user → req.user(在 validateSession() 验证 JWT 声明后设置)
  • requiresAuth() 是 3 行自定义代码,不是 SDK 导入项。
Flask / Python
  • 移除 authlib;添加 descope Python SDK
  • 完全移除 /callback 路由 — 无需代码交换
  • /login 渲染 Descope Web 组件,而不是调用 authorize_redirect()
  • 登出:调用 descope_client.logout(refresh_token) + 删除 cookies
  • 移除 Flask session;状态存储在 DS/DSR cookies 中

重要注意事项:

  • 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-sdk
  • UserProvider → 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()
  • 将 DS Cookie 作为 Authorization: Bearer <DS> 从 Next.js 转发到 API
  • 不需要单独的访问令牌——会话令牌就是承载令牌
FastAPI / Python
  • 移除 auth0-fastapi(AuthConfig、自动挂载的 /api/auth/* 路由、require_session)
  • 添加自定义 TokenVerifier 类:读取 Authorization 标头,根据 Descope JWKS 验证令牌,并将声明作为 FastAPI Security() 依赖附加
  • 不会自动挂载路由;没有会话存储
路径 A:OIDC 兼容(风险较低,渐进式迁移)

Descope 提供标准 OIDC 端点。如果应用使用 OIDC 客户端库 (express-openid-connect、go-oidc、authlib、@auth0/nextjs-auth0 v4 等),只需 进行少量代码更改,即可将其指向 Descope 的 OIDC 颁发者,而非 Auth0:

端点Auth0Descope
颁发者https://YOUR_DOMAIN.auth0.comhttps://api.descope.com
授权https://YOUR_DOMAIN.auth0.com/authorizehttps://api.descope.com/oauth2/v1/authorize
令牌https://YOUR_DOMAIN.auth0.com/oauth/tokenhttps://api.descope.com/oauth2/v1/token
UserInfohttps://YOUR_DOMAIN.auth0.com/userinfohttps://api.descope.com/oauth2/v1/userinfo
JWKShttps://YOUR_DOMAIN.auth0.com/.well-known/jwks.jsonhttps://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),请将其拆分为两部分:

  1. 控制台设置(无法通过脚本完成):Flows、电子邮件模板、MFA 配置、品牌 / 样式 — 在 Descope Console 中配置这些内容。将其作为 MIGRATION-PLAN.md 中的 Phase 1 检查清单。
  2. 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
登录后 WebhookFlows → 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
Auth0Descope
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(扁平字符串)→ Descope tenants(嵌套对象:{ 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 时):

Auth0Descope
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 FGADescope 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 对应实现。建议采用以下方案:

  1. Agent 在你的数据库中创建一条待审批记录
  2. 前端轮询该记录(或使用 WebSocket)
  3. 用户通过 Descope Flow 或自定义 UI 批准
  4. 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_TOKENAuth0 Management API → token explorer(24 小时令牌)
AUTH0_TENANT_ID你的 Auth0 控制面板 URL
DESCOPE_PROJECT_IDDescope Console → Project Settings
DESCOPE_MANAGEMENT_KEYDescope 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 访问控制的应用必须:

  1. 在 JWT Templates 中配置自定义 aud 声明
  2. 在后端调用 validateSession() 时传入 audience
登出分为两个步骤
  1. 调用 descopeClient.logout(refreshToken) 使服务器端会话失效
  2. 清除 DS 和 DSR Cookie

跳过任一步骤都会导致状态异常。

服务器端的个人资料更新不会立即反映在会话令牌中

Auth0 的 appClient.updateSession() 没有直接对应的 Descope 服务器端方法。通过 Management SDK 修改个人资料不会更新浏览器中已有的 JWT。可选方案有四种:

  1. 等待自动刷新(默认约 5 分钟)——无需编写代码;对大多数应用来说可以接受。
  2. 在客户端调用 useDescope().refresh()——立即触发令牌刷新。要求个人资料表单是包含 useDescope() Hook 的客户端组件。完整代码模式见 references/implementation-nuances.md → 会话刷新部分。
  3. Update JWT 端点(POST /v1/mgmt/user/jwt/update)——服务器端方法;更新特定用户已存储 JWT 中的自定义声明。使用前请对照 Descope 文档核实当前行为——此方法更新的是已存储的声明,而非实时会话令牌。
  4. 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 的服务器端辅助函数之前:

  1. 检查项目的 package.json,确认 Next.js 版本。
  2. 如果版本 ≥ 15:编写 await cookies(),并将其所在函数标记为 async。
  3. 沿调用链向上追踪——将读取 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/...' → 导入已过时;重新运行阶段 0
  • Property '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
  1. 迁移内容 — 使用表格列出每个 Auth0 概念及其对应的 Descope 替代方案

  2. 行为差异和待解决问题 — 使用编号列表列出 Auth0 和 Descope 实现之间的重要差异。每项须说明:Auth0 的行为、Descope 的行为、所需操作。

  3. 部署前检查清单 — 使用可执行的复选框项目,列出迁移后的应用运行前必须完成的所有事项。醒目列出所有 Console 设置任务——这些事项最容易被遗漏,因为即使不完成它们,代码也能编译通过。


步骤 7:输出格式

使用 Markdown 编写编号迁移指南,并根据用户的技术栈调整范围。使用代码片段和直接文档链接。始终包含 MIGRATION-SUMMARY.md 交付物(步骤 6)。

对于复杂迁移(FGA、CIBA、AI 工具),明确标注高工作量项目,并估算复杂度(低/中/高),以便用户进行规划。


参考文件

按语言查看会话验证
SDK(GitHub)

评论

支持 Markdown