---
title: 设备码授权流程
description: 使用 Device API，让 CLI、启动器和其他公共客户端通过浏览器确认的用户码完成登录。
editUrl: true
head: []
template: doc
sidebar:
  order: 1
  hidden: false
  attrs: {}
pagefind: true
draft: false
---

设备码授权适合不能安全保存应用 client-auth 私钥的客户端：CLI、启动器、终端工具、共享设备，以及其他公共客户端。客户端向 Sudomimus 请求一组短暂有效的 `deviceCode` / `userCode`，把用户码展示给用户，引导用户到浏览器确认，然后轮询直到批准变成普通的 Sudomimus 应用令牌。

这条流程遵循 [OAuth 2.0 Device Authorization Grant（RFC 8628）](https://www.rfc-editor.org/rfc/rfc8628) 的模型：发起客户端拿到 device code 和 user code，用户在有浏览器能力的 user agent 中批准，客户端持续轮询直到授权完成。Sudomimus 保留标准 device-flow 形状，但最终返回的是 Sudomimus 应用令牌。

它是独立于 Connect 和 Native direct-issue 的接入路径：

| 路径 | 请求靠什么证明 |
|---|---|
| Connect | 应用私钥签出的 client-auth JWT |
| Native direct-issue | Steam ticket 或 AccessKey secret 这样的平台凭据 |
| 设备码授权 | 公共客户端开启码会话，浏览器里的用户批准它 |

公开 HTTP 服务是 `device-api.sudomimus.com`。浏览器批准页面仍然由 `via.sudomimus.com` 承载。

## 协议一览

| 步骤 | 发起方 | 端点 | 结果 |
|---|---|---|---|
| 1. 开始 | 客户端 | `device-api POST /device-authorize` | `{ deviceCode, userCode, verificationUri, verificationUriComplete, expiresIn, interval }` |
| 2. 批准 | 浏览器中的用户 | `via.sudomimus.com/device` | 用户登录、确认显示的码，并批准或拒绝 |
| 3. 轮询 | 客户端 | `device-api POST /device-token` | 等待状态、轮询指令、拒绝、过期，或 `{ accessToken, refreshToken }` |
| 4. 继续使用 | 客户端 | `connect-api POST /refresh` | 后续令牌轮换使用普通 Connect 令牌操作 |

只有客户端能看到 `deviceCode`。只有用户看到并确认 `userCode`。`/device-token` 成功后会消费这次设备会话，所以同一个 `deviceCode` 不能再签发第二组令牌。

## 1. 开启设备授权

客户端先提交应用 anchor：

```bash
curl -X POST https://device-api.sudomimus.com/device-authorize \
  -H "Content-Type: application/json" \
  -d '{
    "applicationAnchor": "your-application"
  }'
```

成功响应：

```json
{
  "applicationAnchor": "your-application",
  "deviceCode": "dvc_...",
  "userCode": "WDJB-MJHT",
  "verificationUri": "https://via.sudomimus.com/device",
  "verificationUriComplete": "https://via.sudomimus.com/device?user_code=WDJB-MJHT",
  "expiresIn": 600,
  "interval": 5
}
```

`/device-authorize` **不**接收 client-auth JWT。应用通过配置选择开放这条路径：它必须有一条启用的 Layer 3 `DEVICE_CODE` ReturnRule。如果缺少这条规则，请求会被拒绝。

## 2. 把用户送到浏览器

在客户端界面清楚展示 `userCode`，并让用户打开浏览器批准页面：

```text
访问 https://via.sudomimus.com/device
输入验证码：WDJB-MJHT
```

如果可以，优先打开 `verificationUriComplete`。它会预填用户码，也最适合做成二维码或终端里的可点击链接：

```text
https://via.sudomimus.com/device?user_code=WDJB-MJHT
```

浏览器页面会再次展示应用和验证码，让用户确认自己批准的是同一个客户端会话。浏览器永远不会收到 `deviceCode`，也不会显示 access token 或 refresh token；它只负责批准或拒绝这次待处理会话。

## 3. 轮询令牌

客户端用私有的 `deviceCode` 轮询 `/device-token`：

```bash
curl -X POST https://device-api.sudomimus.com/device-token \
  -H "Content-Type: application/json" \
  -d '{
    "deviceCode": "dvc_..."
  }'
```

轮询频率不要快于返回的 `interval`。用户还在操作时，`/device-token` 会返回 OAuth 风格的轮询错误：

```json
{
  "error": "authorization_pending"
}
```

批准完成后，同一个端点会返回普通 Sudomimus 应用令牌：

```json
{
  "applicationAnchor": "your-application",
  "accessToken": "...",
  "refreshToken": "...",
  "claims": {
    "email": { "requirement": "OPTIONAL", "state": "GRANTED" },
    "firstName": { "requirement": "OFF", "state": "UNKNOWN" },
    "lastName": { "requirement": "OFF", "state": "UNKNOWN" }
  }
}
```

`claims` 块展示应用的 claim policy 与用户当前共享决定的合并结果。实际 token payload 仍遵循普通 Sudomimus token 规则。

## 4. 后续令牌操作走 Connect

设备码授权只负责最初这次公共客户端交换。一旦 `/device-token` 成功，refresh token 就属于普通 Sudomimus 应用会话模型。

后续使用 Connect API 令牌操作：

- `POST /refresh` 轮换 refresh token 并签发新的 access token。
- `POST /logout` 结束当前 refresh-token family。
- `POST /introspect` 检查 token。
- `POST /revoke-all` 做应用级会话吊销。

这些操作见[管理会话](/zh-cn/guides/managing-sessions/)；轮询状态机见[设备码轮询与错误](/zh-cn/device/polling-and-errors/)。

## 应用配置

应用必须允许浏览器侧认证和 realize 检查通过：

| 层 | 要求 |
|---|---|
| Layer 1 | 现有认证方式，例如邮箱验证码或通行密钥 |
| Layer 2 | 能允许该账户的现有身份规则 |
| Layer 3 | 一条 `DEVICE_CODE` ReturnRule |

`DEVICE_CODE` 是 Layer 3 返回方式，不是新的认证方式。用户仍然通过应用已有的 Layer 1 方法登录，也仍然要通过 Layer 2 检查后，设备会话才能被批准。

## 什么时候选它

当客户端是公共客户端、无法保密 client-auth 私钥时，选择设备码授权。典型场景包括发给用户安装的 CLI、桌面启动器、纯终端环境，或者需要用户在另一台有浏览器的设备上完成登录的共享屏幕设备。

如果你有能保护 client-auth 私钥的机密后端，优先考虑 [Connect 浏览器轮询](/zh-cn/native/overview/#浏览器轮询)。如果客户端拥有 Steam ticket 或预签发 AccessKey 这样的平台凭据，使用 [Native direct-issue](/zh-cn/native/overview/)。

原始端点契约见 [Device API 参考](/zh-cn/api/device/)。