gcloud auth login 类似:device_code + user_code)user_code 并登录、确认授权access_token(及可选的 refresh_token / id_token)client_id)redirect_uri,无需为 CLI 配置回调地址client_secret| 字段 | 说明 |
|---|---|
device_authorization_endpoint | 设备授权请求端点 |
token_endpoint | 令牌端点(轮询) |
grant_types_supported | 含 urn:ietf:params:oauth:grant-type:device_code |
https://api.yearnstudio.cn┌─────────┐ ┌──────────────┐ ┌────────────┐
│ CLI │ │ ShangCloud │ │ 用户浏览器 │
└────┬────┘ └──────┬───────┘ └─────┬──────┘
│ POST /oauth/device_authorization │ │
│ client_id, scope │ │
│──────────────────────────────────>│ │
│ device_code, user_code, │ │
│ verification_uri, interval │ │
│<──────────────────────────────────│ │
│ │ │
│ 展示 user_code + 打开验证页 URL │ │
│───────────────────────────────────┼───────────────────────────────>│
│ │ 登录 + 输入 user_code + 同意 │
│ │<───────────────────────────────│
│ │ 标记授权成功 │
│ │ │
│ 轮询 POST /oauth/token │ │
│ grant_type=device_code │ │
│──────────────────────────────────>│ │
│ authorization_pending / token │ │
│<──────────────────────────────────│ │| 参数 | 必填 | 说明 |
|---|---|---|
client_id | 是 | 应用 Client ID |
scope | 否 | 权限范围,空格或逗号分隔。默认 openid |
client_secret | 条件 | 默认必填;应用开启「公开客户端 PKCE」且同时提交 code_challenge 时可省略 |
code_challenge | 条件 | PKCE challenge。免 secret 时必填;有 secret 时可选 |
code_challenge_method | 否 | S256(推荐)或 plain,默认 S256 |
Authorization: Basic base64(client_id:client_secret)。公开客户端 PKCE:应用设置 allow_public_pkce默认关闭。开启后,设备码 / 授权码流程可在使用 PKCE 时不传client_secret。若申请时带了code_challenge,轮询时必须带匹配的code_verifier。
200{
"device_code": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"user_code": "ABCD-EFGH",
"verification_uri": "https://api.yearnstudio.cn/oauth/device",
"verification_uri_complete": "https://api.yearnstudio.cn/oauth/device?user_code=ABCD-EFGH",
"expires_in": 900,
"interval": 5
}| 字段 | 说明 |
|---|---|
device_code | 仅保存在 CLI 侧,用于轮询换取令牌,切勿展示给用户 |
user_code | 展示给用户输入的短码(格式 XXXX-XXXX) |
verification_uri | 用户应打开的验证页 |
verification_uri_complete | 已预填 user_code 的链接(可直接打开) |
expires_in | 有效期(秒),默认 900(15 分钟) |
interval | 建议轮询间隔(秒),默认 5 |
{
"error": "invalid_client",
"error_description": "Unknown client_id"
}error:invalid_client、invalid_request。verification_uri 或 verification_uri_completeuser_code(若链接已预填则跳过)GET /oauth/device
GET /oauth/device?user_code=ABCD-EFGH
POST /oauth/device # 表单:user_code, action=lookup|allow|deny| 参数 | 必填 | 说明 |
|---|---|---|
grant_type | 是 | 固定为 urn:ietf:params:oauth:grant-type:device_code |
device_code | 是 | 步骤 1 返回的设备码 |
client_id | 是 | 应用 Client ID |
client_secret | 条件 | 默认必填;应用开启公开 PKCE 且步骤 1 使用了 PKCE 时可省略 |
code_verifier | 条件 | 若步骤 1 使用了 PKCE,则必填 |
400:{
"error": "authorization_pending",
"error_description": "The authorization request is still pending"
}interval 秒等待后再次请求。400:{
"error": "slow_down",
"error_description": "Polling too frequently, increase interval"
}{
"error": "access_denied",
"error_description": "The end-user denied the authorization request"
}{
"error": "expired_token",
"error_description": "The device_code has expired"
}200{
"access_token": "<JWT>",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "<opaque>",
"scope": "openid profile",
"id_token": "<JWT>"
}access_token:RS256 JWT,有效期 1 小时refresh_token:不透明串,约 30 天,可用于 grant_type=refresh_token 续期scope 包含 openid 时返回 id_token| Scope | 含义 |
|---|---|
openid | OIDC;会签发 id_token,可识别用户 |
profile | 用户公开资料(昵称、头像等) |
email / user:email | 邮箱相关 |
user:basic | 用户基本信息 |
var:io | 云变量读写 |
mmo | 多人联机 |
openid profile user:basic。device_code 仅保存在进程内存,不要写入日志或发给用户user_code 可展示,有效期短(默认 15 分钟),一次性使用interval,收到 slow_down 后加大间隔client_secret;无法保存密钥的 CLI 需在开发者中心开启「公开客户端 PKCE」,并使用 PKCE(S256)access_token / refresh_token 按密钥保管,勿提交到仓库code_verifier 仅保存在 CLI 进程内,不要写入日志allow_public_pkce 时,无 secret 的请求一律拒绝(即使带了 PKCE)| 授权码 + PKCE | 设备授权码 | |
|---|---|---|
| 适用场景 | Web / 桌面(可打开回调) | CLI / 输入受限设备 |
是否需要 redirect_uri | 是 | 否 |
| 用户交互 | 浏览器跳转回应用 | 浏览器输入短码 |
| Token 获取 | 用 code 换 token | 用 device_code 轮询 |
grant_type | authorization_code | urn:ietf:params:oauth:grant-type:device_code |
error | 含义 | CLI 行为 |
|---|---|---|
authorization_pending | 用户尚未完成授权 | 等待 interval 后重试 |
slow_down | 轮询过快 | 间隔 +5s 后重试 |
access_denied | 用户拒绝 | 终止并提示 |
expired_token | 设备码过期 | 重新申请设备码 |
invalid_grant | 码无效或不属于该 client | 终止 |
invalid_client | 客户端凭证错误 | 检查 client_id / secret |
{
"device_authorization_endpoint": "https://api.yearnstudio.cn/oauth/device_authorization",
"grant_types_supported": [
"authorization_code",
"refresh_token",
"urn:ietf:params:oauth:grant-type:device_code"
],
"code_challenge_methods_supported": ["plain", "S256"]
}/.well-known/openid-configurationGET /oauth/userinfo