完成第一次登录
本教程会带一个 Web 应用从门户配置一直走到第一次完整登录。完成后,你的后端将持有一位已通过 Sudomimus 认证的用户所对应的 access token 与 refresh token。
不是 Web 应用?请选对应指南:
-
在
with.sudomimus.com创建或加入一个组织(Organization)。 开发者自助门户以组织为单位:应用(Application)与扇区(Sector)都归属于某个组织,因此在创建应用之前你需要先拥有一个。大多数账户会当场创建自己的第一个组织(表单会预填一个建议名称);如果同事已经在运行一个,请让他们邀请你加入。在你尚未归属任何组织之前,/applications与/sectors页面会重定向到/organizations。 -
在该组织内创建你的应用。 创建时你会拿到:
applicationAnchor—— 一个稳定的小写 kebab-case 应用锚点(例如my-app),也是应用在 API 中的公开名称。- client-auth 私钥 —— 创建时只展示一次,用于签名
/establish请求。请像对待任何生产密钥一样妥善保管。 - 每个应用都有一个 Session JWKS URL:
https://session-api.sudomimus.com/applications/{applicationAnchor}/jwks.json,按kid验证 access / refresh token。密钥轮换在应用详情的“签名密钥”标签页管理;创建响应不会下发一份一次性的签名 PEM。
-
至少添加一条
CALLBACK类型的 返回规则,列出允许重定向回的 hostname。具体的callbackUrl在每次/establish时由应用提供;规则决定的是这个 URL 的 hostname 是否被允许。 -
至少添加一条认证规则(例如
PASSKEY_USERNAMELESS、PASSKEY_REASONED或EMAIL_VERIFICATION)和一条身份准入规则(例如用于开放注册的EMAIL+allowedEmails: ["*"])。三层规则都采用允许列表 + 默认拒绝;任一层为空时,应用都无法完成登录。 -
激活应用。 新应用初始状态为
DRAFT。上线准备、激活、停用与重新启用的权威说明见应用上线。
每一次经过 Connect API 的身份认证往返都有三个阶段,随后进入共享的 Session API refresh 阶段:
- Establish(建立) —— 应用后端请求 Connect 开启一次认证会话,并取回一对会话引用(
exposureKey+hiddenKey)。 - Authenticate(认证) —— 应用携带
exposureKey把用户引导到via.sudomimus.com;用户在那里完成通行密钥或邮箱验证码挑战。 - Redeem(兑换) ——
via.sudomimus.com通过回调 URL 交还控制权,并在查询参数中附带exposure-key和confirmation-key。应用后端将三个密钥提交给 Connect,换取签名的访问令牌和刷新令牌。 - Refresh(刷新) —— 访问令牌临近过期时,应用后端调用 Session API,使用刷新令牌换取新的访问令牌和轮换后的刷新令牌。
完整请求形状与 Connect、via.sudomimus.com、应用之间的协作关系见 Connect 流程。
完成第一次登录
Section titled “完成第一次登录”下面是与框架无关的后端骨架。请把 pendingSessions 和响应辅助函数替换为你的框架所提供的服务端 session store 与 HTTP 原语。绝不能把 client-auth 私钥或 hiddenKey 放进浏览器代码。
1. 安装并配置客户端
Section titled “1. 安装并配置客户端”pnpm add @sudomimus/connect以下值只能放在后端环境中:
SUDOMIMUS_APPLICATION_ANCHOR=your-applicationSUDOMIMUS_CLIENT_AUTH_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"SUDOMIMUS_CALLBACK_URL=https://your-app.com/auth/callbackcallback hostname 必须符合你在门户中配置的 CALLBACK Return Rule。
2. 从后端路由发起登录
Section titled “2. 从后端路由发起登录”import { ConnectClient, RETURN_METHOD } from "@sudomimus/connect";
const applicationAnchor = process.env.SUDOMIMUS_APPLICATION_ANCHOR!;const client = new ConnectClient({ clientAuth: { applicationAnchor, privateKeyPem: process.env.SUDOMIMUS_CLIENT_AUTH_PRIVATE_KEY!, },});
const inquiry = await client.establish({ applicationAnchor, returnMethods: [{ type: RETURN_METHOD.CALLBACK, payload: { callbackUrl: process.env.SUDOMIMUS_CALLBACK_URL! }, }],});
await pendingSessions.save(inquiry.exposureKey, inquiry.hiddenKey);
const hostedLogin = new URL("https://via.sudomimus.com/");hostedLogin.searchParams.set("exposure-key", inquiry.exposureKey);return redirect(hostedLogin.toString(), 302);在浏览器中打开这个路由。Sudomimus 会展示 Layer 1 规则所允许的认证方式之一;使用测试账户完成挑战。
3. 在后端兑换 callback
Section titled “3. 在后端兑换 callback”认证完成后,Sudomimus 会把浏览器重定向到 callback,并附上 exposure-key 与 confirmation-key 查询参数:
const callbackUrl = new URL(request.url);const exposureKey = callbackUrl.searchParams.get("exposure-key");const confirmationKey = callbackUrl.searchParams.get("confirmation-key");
if (exposureKey === null || confirmationKey === null) { throw new Error("Missing Sudomimus callback keys");}
const hiddenKey = await pendingSessions.take(exposureKey);const tokens = await client.redeem({ exposureKey, hiddenKey, confirmationKey,});take 应原子地消费服务端暂存值,使 callback 无法复用它。兑换成功后会返回 accessToken 与 refreshToken。
4. 验证结果
Section titled “4. 验证结果”使用应用的 Session JWKS 验证 tokens.accessToken,检查签名、kid、typ、issuer、audience、过期时间和 actor shape;验证成功后,从 sub 读取应用可见的用户标识符。请遵循完整的令牌验证流程,不要把仅仅 decode 当作验证。
把 refresh token 存入受保护的服务端存储,再按照管理会话完成轮换。callback 只能成功兑换一次、token 验证通过、应用建立自己的本地 session,并且日志和 URL 都没有泄露 token 时,第一次登录路径才算完成。