离开 Auth0:到底有哪些东西会迁走,以及他们唯一不肯交出的那一样
由 AI 从英文原文翻译。 阅读原文
大多数团队离开 Auth0 并不是因为讨厌它。他们离开,是因为账单暴涨,或是因为 SAML 和 SCIM 原来被关在按连接计费的企业版套餐背后,而每个新客户的 SSO 链接都会让计费表往上跳。然后他们一想到要真正迁移自己的身份提供方,觉得听起来太吓人,于是又留了一年。
它没有看上去那么吓人。下面就讲清楚一次真实的 Auth0 迁移到底涉及什么(无聊的部分、繁琐的部分,以及唯一一处真正困难的部分),让你自己来判断。
你的 Auth0 租户里有什么
有几样东西必须落到新的地方:
- 应用程序 → OAuth/OIDC 客户端。回调地址、登出 URL、允许的来源、授权类型,以及客户端密钥。机械活。
- API(资源服务器)+ scope → audience 和 scope,与使用它们的客户端关联起来(Auth0 把这记作「client grants」)。
- 角色及其分配 → 角色 + 按用户的角色关联。
- 连接 → 企业(OIDC/SAML)、社交和数据库连接。企业 OIDC 能干净地映射到一个联合提供方;其余的你重新配置即可。
- 用户 → 资料、元数据,以及已关联的社交/企业身份。
这些原则上都不难。紧张感来自三件具体的事。
让人紧张的三件事
**1. 保持身份标识稳定。**你的用户在各处都通过他们的 sub 被引用(你的应用则通过 client_id):下游应用持有的 refresh token、客户 IdP 里的 SCIM 行、存在你自己数据库里的用户 ID。如果一次迁移生成了新的 ID,所有这些都会悄无声息地坏掉。解决办法说起来简单,做对却至关重要:把 Auth0 的 user_id 保留为 sub,并把 client_id 原样保留。这样下游就什么都察觉不到。
**2. 密码,真正困难的那一件。**Auth0 的 Management API 从不返回密码哈希。这是 Auth0 刻意为之的政策,不是你工具的缺陷。你有两条诚实的路:
- 申请 Auth0 的支持团队协助的批量导出,它会给你一个 NDJSON 文件,里面是每个用户的 bcrypt 哈希。bcrypt 是可移植的:任何能校验 bcrypt 的系统都可以原样接收这些哈希,你的用户什么都不用重置。
- 或者彻底跳过哈希,让用户在首次登录时设置新密码。没有任何东西「丢失」(本来就没有哈希可带)但对你的用户来说这是一个看得见的步骤。
哈希没有任何自助式 API。谁要是告诉你不需要那个支持文件、一键 Auth0 导出就包含密码,那他是在含糊其辞。
**3. 1,000 个用户的上限。**Auth0 的用户列表 API 最多返回 1,000 个用户。对于更大的租户,批量导出文件(就是携带哈希的那个)才是真正、完整的用户来源,而不是实时 API。
把它变成一键操作
这就是我们在 Authagonal 里所构建的。你把导入工具指向一个 Auth0 machine-to-machine 应用(仅读取 scope),它就会:
- 先运行一次只读预览:它会清点将要导入的每一个应用、API、角色、连接和用户,并标记出任何需要注意的地方。在你确认之前,什么都不会写入。
- 把应用程序、API 的 scope/audience、角色 + 分配、用户 + 元数据,以及企业 OIDC 连接迁移过来,并保留
sub和client_id,让现有的 token 和引用继续能够解析。 - 重新哈希 Auth0 的(读取时为明文的)客户端密钥,让你的应用无需轮换就能继续完成认证。
- 如果你提供了导出文件,就原样导入 bcrypt 密码哈希,而那个文件也会解除 1,000 个用户的上限。没有导出文件?用户在首次登录时设置密码。
而且,由于企业功能(SAML、SCIM、MFA、审计日志、自定义域名)包含在每一个套餐里,而不是按连接计费,那个把你推向出口的东西,并不会在另一头等着你。
关于测试迁移的一点题外话
我们用一个真实的、已填充数据的数据库来测试导入工具,而不是用 mock,结果证明这很值。ASP.NET Identity 把 LockoutEnd 存为 datetimeoffset,而用 GetDateTime() 去读取这种类型会抛出异常。仅仅一个被锁定的用户,就会让整次导入失败。这种问题,只有用真正的导入工具去跑真实数据才抓得到。如果你在评估任何迁移工具,问问它是怎么测试的:「我们 mock 源 API」和「我们对着一个有数据的租户来跑」并不是一回事。
如果你正盯着那扇出口
迁移比你担心的更无聊(先预览,保留你的 ID,定下你的密码路线)唯一真正的限制就是 Auth0 的哈希导出。如果你想看看从你的租户里会迁移过来什么,预览是只读的,会在你确认之前把一切都展示给你。
→ 迁出 Auth0