随着 AI Agent 和开发者工具的发展,CLI 正重新成为常见的交互与集成入口。GitHub CLI gh、Lark/Feishu lark-cli、Codex CLI 等工具在调用云端 API 时,都需要完成用户授权,而 OAuth Device Flow 正是这类场景中常见的一种方式。
OAuth Device Flow,也叫 Device Authorization Flow,主要用于那些不方便打开浏览器、不适合输入密码,或者无法接收 redirect URI 回调的设备和工具,例如智能电视、游戏机、IoT 设备、服务器终端和 CLI 工具。
它的核心思路可以概括为:
设备不直接让用户输入密码,而是显示一个短码;用户用手机或电脑打开浏览器完成登录授权;设备在后台轮询,直到拿到 access token。
它解决什么问题
普通 OAuth Authorization Code Flow 通常依赖浏览器跳转和 redirect URI。桌面应用可以在本机启动一个回调服务,Web 应用可以接收服务器回调,但很多设备做不到:
- 电视、游戏机输入账号密码很麻烦;
- CLI 工具可能运行在没有浏览器的 SSH 环境里;
- IoT 设备通常没有完整浏览器,也没有稳定公网回调地址;
- 用户密码和 MFA 不应该输入到不可信或输入体验差的设备上。
Device Flow 的作用,就是把登录和授权动作转移到用户更方便操作的手机或电脑上完成。
参与角色
- Device Client:受限设备或 CLI 工具,负责显示验证码并轮询 token。
- Authorization Server:OAuth 授权服务器,负责生成验证码、处理登录授权、发放 token。
- User:用户本人,用手机或电脑完成授权。
- Resource Server:真正提供 API 的服务,例如 GitHub API、Google Drive API。
完整流程
1. 设备申请 device code
设备先向授权服务器请求一组用于设备授权的码:
POST /oauth/device/code
Content-Type: application/x-www-form-urlencoded
client_id=abc123&scope=repo read:user
这里通常包含:
client_id:客户端标识;scope:希望申请的权限范围。
Device Flow 的客户端通常是 public client,不能安全保存 client_secret。
2. 授权服务器返回验证码信息
授权服务器返回类似结果:
{
"device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
"user_code": "WDJB-MJHT",
"verification_uri": "https://example.com/device",
"verification_uri_complete": "https://example.com/device?user_code=WDJB-MJHT",
"expires_in": 900,
"interval": 5
}
字段含义:
| 字段 | 作用 |
|---|---|
device_code |
给设备使用的长码,后续轮询 token 时提交 |
user_code |
给用户看的短码,用户在网页上输入 |
verification_uri |
用户需要打开的授权页面 |
verification_uri_complete |
已带上 user code 的完整授权链接,用户打开后可能不必手动输入 |
expires_in |
这组码的有效期,单位通常是秒 |
interval |
设备轮询 token 接口的最小间隔 |
3. 设备提示用户授权
设备或 CLI 显示:
请打开下面的链接完成授权:
https://example.com/device
然后输入验证码:
WDJB-MJHT
如果有 verification_uri_complete,也可以直接显示完整链接:
https://example.com/device?user_code=WDJB-MJHT
4. 用户在浏览器里登录并确认
用户用手机或电脑打开授权页面,输入验证码,登录账号,并确认是否允许这个应用访问指定权限。
授权服务器会更新这次设备授权请求的状态:已授权、被拒绝,或者已过期。
5. 设备轮询 token 接口
设备从拿到 device_code 开始,按 interval 指定的间隔请求 token 接口:
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
client_id=abc123&device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS&grant_type=urn:ietf:params:oauth:grant-type:device_code
关键参数是:
grant_type=urn:ietf:params:oauth:grant-type:device_code
它表示客户端正在用 Device Flow 的授权结果换取 token。
6. 授权成功后返回 access token
用户完成授权后,设备下一次轮询会收到:
{
"access_token": "access_token_here",
"token_type": "Bearer",
"scope": "repo read:user",
"expires_in": 3600,
"refresh_token": "refresh_token_here"
}
之后设备就可以带着 access token 调用资源服务器:
GET /user
Authorization: Bearer access_token_here
流程图
设备 / CLI 授权服务器 用户浏览器
| | |
| 申请 device_code | |
|----------------------------->| |
| 返回 device_code/user_code | |
|<-----------------------------| |
| 显示 URL 和 user_code | |
| | 用户打开页面、输入 code、登录 |
| |<----------------------------->|
| 轮询 token 接口 | |
|----------------------------->| |
| authorization_pending | |
|<-----------------------------| |
| 继续轮询 | |
|----------------------------->| |
| 返回 access_token | |
|<-----------------------------| |
轮询时的几种状态
设备轮询 token 接口时,授权不一定已经完成。常见返回状态如下:
| 错误码 | 含义 | 客户端应该怎么做 |
|---|---|---|
authorization_pending |
用户还没有完成授权 | 继续等待,按 interval 轮询 |
slow_down |
轮询太频繁 | 增加轮询间隔 |
access_denied |
用户拒绝授权 | 停止流程,提示授权被拒绝 |
expired_token |
device code 已过期 | 停止流程,让用户重新发起登录 |
invalid_client |
client_id 不合法 | 检查客户端配置 |
invalid_grant |
device_code 无效或状态异常 | 停止流程,重新开始 |
客户端不应该把 authorization_pending 当成失败。它只是表示用户还没完成网页端授权。
为什么 Device Flow 适合 CLI、电视和 IoT 设备
Device Flow 的优势在于:
- 设备不需要打开浏览器;
- 设备不需要接收 redirect URI 回调;
- 用户不用在设备上输入密码和 MFA;
- 登录和授权发生在授权服务器的正规网页上;
- CLI 或设备只需要显示短码,并在后台轮询。
所以它尤其适合输入能力弱、没有浏览器、没有公网回调地址的场景。
安全要点
Device Flow 的安全性依赖几个关键设计:
-
用户密码不进入设备
用户只在授权服务器网页上登录,设备只拿到 token。 -
user code 短但有效期也短
短码方便输入,但也更容易被猜,所以必须设置过期时间、错误次数限制和风控。 -
轮询必须限速
客户端要遵守interval,遇到slow_down要放慢请求,避免压垮授权服务器。 -
授权页面必须展示应用和权限
用户需要清楚看到哪个应用在请求哪些权限,避免误授权。 -
适合 public client
电视、CLI、IoT 设备通常不能安全保存密钥,因此 Device Flow 不依赖客户端安全保存client_secret。
小结
Device Flow 可以压缩成 6 步:
- 设备向授权服务器申请
device_code; - 授权服务器返回
device_code、user_code和授权 URL; - 设备显示 URL 和
user_code; - 用户在另一台设备上打开网页,登录并授权;
- 设备按间隔轮询 token 接口;
- 授权完成后,设备拿到 access token 并调用 API。
一句话总结:
Device Flow 是 OAuth 为受限设备设计的授权方式:设备显示短码,用户在浏览器里授权,设备轮询直到拿到 token。