跳转到内容

设备码轮询与错误

查看 Markdown

设备码授权客户端的大部分时间都在等待。好的实现会把 /device-token 当作一个状态机:pending 继续轮询,slow_down 放慢速度,终止错误停止流程,成功则消费这次会话。

POST /device-authorize 之后,保存 deviceCode,展示 userCode,然后用不快于返回 interval 的频率开始轮询。

let intervalSeconds = authorize.interval;
while (true) {
await sleep(intervalSeconds * 1000);
const res = await fetch("https://device-api.sudomimus.com/device-token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ deviceCode: authorize.deviceCode }),
});
const body = await res.json();
if (res.ok) {
return body; // { accessToken, refreshToken, claims, ... }
}
if (body.error === "authorization_pending") continue;
if (body.error === "slow_down") {
intervalSeconds = body.interval ?? intervalSeconds + 5;
continue;
}
throw new Error(body.error);
}

如果客户端轮询太快,服务端可能返回 slow_down。发生这种情况后,后续轮询使用响应里的 interval

POST /device-token 对轮询状态使用 RFC 8628 device-flow 错误词汇。客户端应该按 error 分支处理;不要期待这里返回 Sudomimus { "reason": "..." } wire reason。

Error含义客户端行为
authorization_pending用户还没有批准或拒绝。按当前间隔继续轮询。
slow_down客户端轮询太快。增加间隔;如果响应带 interval,使用它。
access_denied用户拒绝、批准失败,或策略已不再允许签发。停止轮询,展示拒绝/失败状态。
expired_token设备授权会话已过期。停止轮询;重新从 /device-authorize 开始。
invalid_requestdeviceCode 格式错误、未知,或已经被消费。停止轮询;必要时重新开始。
server_error批准后签发 token 失败。停止轮询,报告可重试的服务故障。

成功响应使用 Sudomimus 普通 camelCase JSON 形状。轮询失败刻意使用 device-flow 的 error 词汇,这样公共客户端可以按熟悉的设备码状态机实现。

每个设备授权会话都很短暂。生产默认值目前是 expiresIn: 600 秒,但客户端应该使用 /device-authorize 返回的值,而不是硬编码生命周期。

一旦 /device-token 成功,这次会话就被消费。用同一个 deviceCode 重复调用 /device-token 会返回 invalid_request,不能再签发第二组令牌。

两个 code 的处理方式不同:

谁能看到用途
deviceCode只有发起客户端/device-token 的高熵 bearer secret
userCode用户和浏览器批准页面用户比较并确认的短码

不要展示 deviceCode,不要写入日志,不要放进浏览器 URL,也不要发给你的应用后端,除非那个后端就是负责轮询 /device-token 的组件。deviceCode 在过期前是 bearer secret;谁拿到它,谁就能轮询并消费已批准的会话。

userCode 可以展示,但它不是 token,也不能独自签发 token。它的作用是让浏览器里的用户确认:自己批准的正是终端、启动器或设备界面上显示的那次客户端会话。

设备码授权是为公共客户端准备的。/device-authorize 不需要 client-auth JWT,因为这样的客户端无法保护签名密钥。Sudomimus 改由应用配置来把关:

  • applicationAnchor 必须解析到一个启用的应用。
  • 应用必须有一条启用的 Layer 3 DEVICE_CODE ReturnRule。
  • 浏览器批准仍然走应用的 Layer 1 认证规则。
  • realize 出来的账户仍然要通过 Layer 2,批准才能完成。

如果你有能保护 client-auth 私钥的机密后端,ConnectConnect 浏览器轮询 可能更合适。

/device-token 返回的 access token 和 refresh token 与其他 Sudomimus 流程相同。Claim 分享同样遵循应用的 claim policy 和用户的 grant state,和 Connect 或 Native direct-issue 一致。

Device API 没有 refresh 端点。初始交换完成后,使用 Connect:

  • connect-api POST /refresh
  • connect-api POST /logout
  • connect-api POST /introspect
  • connect-api POST /revoke-all

令牌生命周期调用见管理会话;精确请求/响应 schema 见 Device API 参考