| 版本 | 1.0(2026-09-15) |
| 域名 | https://www.bangwo8.com |
| 适用对象 | 桌面 App、CLI 工具、MCP 客户端、Web 应用、服务端集成 |
| 模式 | 适用场景 |
|---|---|
| A. 设备授权码流程(RFC 8628) | CLI 工具、桌面 App、无浏览器/无回调地址的环境 |
| B. 网页授权码流程(授权码 + 重定向,PKCE 强制) | Web 应用集成;带回调能力的桌面/移动端(自定义协议回跳) |
| C. 服务端直连密钥 | 服务器到服务器集成,无终端用户授权动作 |
client_id。模式 B 还需登记回调地址白名单。应用注册只支持管理员web操作,暂不开放公开接口注册。
secret_id + secret_key:Authorization: Basic base64(secret_id : secret_key)/mcp、/mcp/user、/mcp/config);secret_id/secret_key 长期有效,权限随授权用户;safeStorage / macOS Keychain / Windows DPAPI);0600 权限);接入应用 www.bangwo8.com 用户浏览器
│ │ │
│ ① POST /oauth/device-code.php │ │
│───────────────────────────────────►│ │
│◄───────────────────────────────────│ │
│ device_code / user_code │ │
│ │ │
│ ② 引导用户打开 │ │
│ verification_uri_complete │ │
│────────────────────────────────────┼───────────────────────────────────►│
│ │ │
│ │ ③ GET /oauth/authorize.php │
│ │◄───────────────────────────────────│
│ │ │
│ │ ④ 管理员登录 + 确认授权 │
│ │◄───────────────────────────────────│
│ │ │
│ ⑤ 按 interval 轮询 │ │
│ POST /oauth/token.php │ │
│───────────────────────────────────►│ │
│◄───────────────────────────────────│ │
│ 400 authorization_pending │ │
│ │ │
│ POST /oauth/token.php (重试) │ │
│───────────────────────────────────►│ │
│◄───────────────────────────────────│ │
│ 200 {secret_id, secret_key} │ │
│ │ │
│ ⑥ 安全存储凭证,正常调用 API │ │
│ │ │POST /oauth/device-code.php(Content-Type: application/json)| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
client_id | string | 是 | 平台登记的应用标识 |
device_name | string | 是 | 设备描述,建议格式:{用户名}的{应用名}中的{设备类型};最长 200 字符 |
{
"device_code": "550e8400-e29b-41d4-a716-446655440000",
"user_code": "ABCD-1234",
"verification_uri": "https://www.bangwo8.com/oauth/authorize.php",
"verification_uri_complete": "https://www.bangwo8.com/oauth/authorize.php?user_code=ABCD-1234",
"expires_in": 900,
"interval": 3
}| 字段 | 说明 |
|---|---|
device_code | 设备码,轮询用,对用户不可见,不得展示给用户 |
user_code | 用户码 XXXX-XXXX(4 位大写字母 + 横杠 + 4 位数字) |
verification_uri_complete | 优先打开此链接(user_code 已自动填充) |
expires_in / interval | 设备码有效期(秒,900)/ 建议轮询间隔(秒,3) |
invalid_client(client_id 未登记)、invalid_request、too_many_requests(429,单 IP 每分钟 10 次,带 Retry-After 头)。POST /oauth/token.php(Content-Type: application/json){
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
"device_code": "550e8400-e29b-41d4-a716-446655440000",
"client_id": "qianchui_desktop"
}同源约束: client_id必须与申请该device_code的客户端一致。
| HTTP | error | 客户端行为 |
|---|---|---|
| 200 | —(返回 secret_id/secret_key) | 停止轮询,安全存储凭证 |
| 400 | authorization_pending | 等待 interval 秒后继续 |
| 400 | expired_token | 终止,提示用户重新发起授权 |
| 400 | invalid_grant | 终止(device_code 无效/已使用/跨客户端) |
| 400 | invalid_client / unsupported_grant_type / invalid_request | 终止,修正请求 |
GET /oauth/authorize.php?user_code=XXXX-XXXX(用户浏览器打开)接入应用 www.bangwo8.com 用户浏览器
│ │ │
│ ① 生成 state + code_verifier │ │
│ / code_challenge (S256) │ │
│ │ │
│ ② 302 重定向浏览器 │ │
│──────────────────────────────────────┼───────────────────────────────────►│
│ GET /oauth/authorize-web.php │ │
│ ?client_id&redirect_uri&state │ │
│ &code_challenge&response_type=code │ │
│ │ │
│ │ 校验 client_id + redirect_uri │
│ │ 未登录 → 统一登录(登录后回跳) │
│ │ 展示授权确认页 │
│ │ (应用名+回调站点+CSRF令牌) │
│ │ │
│ │ 用户点击"授权" │
│ │◄───────────────────────────────────│
│ │ 生成授权码(10分钟有效,单次使用) │
│ │ │
│ │ 302 重定向 │
│ │───────────────────────────────────►│
│ │ │
│ ③ 302 回调 │ │
│◄─────────────────────────────────────┼────────────────────────────────────│
│ redirect_uri?code=xxx&state=xxx │ │
│ │ │
│ ④ 校验 state(接入端防 CSRF) │ │
│ │ │
│ ⑤ POST /oauth/token.php │ │
│ grant_type=authorization_code │ │
│ &code&redirect_uri │ │
│ &code_verifier&client_id │ │
│─────────────────────────────────────►│ │
│ │ PKCE S256 校验通过后签发 │
│◄─────────────────────────────────────│ │
│ 200 {secret_id, secret_key} │ │
│ │ │
│ ⑥ 安全存储凭证,正常调用 API │ │
│ │ │GET/POST /oauth/authorize-web.php| 参数 | 必填 | 说明 |
|---|---|---|
client_id | 是 | 已登记且启用的应用 |
redirect_uri | 是 | 必须与白名单精确匹配;支持 https 与自定义协议(如 myapp://oauth/callback) |
state | 是 | 1~128 字符随机串,服务端原样回传,接入端校验防 CSRF |
code_challenge | 是 | PKCE S256:base64url(sha256(code_verifier)),固定 43 字符 |
response_type | 否 | 缺省视为 code,传其他值报错 |
redirect_uri?code=..&state=..。POST /oauth/token.php(Content-Type: application/json){
"grant_type": "authorization_code",
"code": "回调收到的授权码",
"redirect_uri": "https://app.example.com/callback",
"code_verifier": "PKCE 原始串",
"client_id": "qianchui_web"
}| 校验项 | 失败响应 |
|---|---|
| code 不存在 / 已使用 / 跨客户端 | 400 invalid_grant |
| code 过期(10 分钟) | 400 expired_token |
| redirect_uri 与授权时不一致 | 400 invalid_grant |
| PKCE:sha256(code_verifier) ≠ 授权时的 code_challenge | 400 invalid_grant |
{secret_id, secret_key}:同一用户对同一应用重新授权复用同一凭证。| HTTP | error | 含义 | 处理方式 |
|---|---|---|---|
| 400 | invalid_request | 参数缺失或格式错误 | 修正请求 |
| 400 | invalid_client | client_id 未登记或未启用 | 终止,联系平台确认 |
| 400 | invalid_grant | 授权码不存在/已使用/跨客户端/redirect_uri 不匹配 | 终止,重新发起授权 |
| 400 | expired_token | 授权码过期(10 分钟) | 终止,重新发起授权 |
| 500 | server_error | 服务端异常 | 稍后重试 |
device_code 不渲染到任何 UI;凭证加密存储;提供"退出登录"功能。1. 启动时注册自定义协议:app.setAsDefaultProtocolClient('myapp')
2. 点"登录":生成 code_verifier + challenge + state
3. shell.openExternal('https://www.bangwo8.com/oauth/authorize-web.php
?client_id=your_client_id&redirect_uri=myapp://oauth/callback
&state=..&code_challenge=..')
4. 用户在浏览器完成授权后,系统唤起 App(open-url / second-instance 事件),
从回调 URL 解析 code 与 state 并校验 state
5. POST /oauth/token.php(grant_type=authorization_code)换 secret_id/secret_key
6. safeStorage 加密落盘;主窗口需要单实例锁保证回调唤起时由已有实例接收redirect_uri),整体分四步。https://www.bangwo8.com/oauth/authorize-web.php?client_id={client_id}&redirect_uri={redirect_uri}&state={state}&code_challenge={code_challenge}务必在跳转前将 state和code_verifier关联存入 session/缓存,回调时校验 state 并用于换码。
redirect_uri?code=xxx&state=xxx:| 参数 | 说明 |
|---|---|
code | 授权码,10 分钟有效,一次性使用,立即拿去换凭证 |
state | 与发起时一致,必须校验,否则拒绝(防 CSRF) |
/oauth/token.php:{secret_id, secret_key},错误响应见 §4.4。Authorization: Basic base64(secret_id:secret_key)| error | HTTP | 含义 | 客户端行为 |
|---|---|---|---|
invalid_request | 400/405 | 参数缺失/非法 JSON/方法不对 | 修正请求 |
invalid_client | 400 | client_id 未登记或未启用 | 终止;联系平台确认 |
unsupported_grant_type | 400 | grant_type 不正确 | 修正请求 |
authorization_pending | 400 | 用户尚未授权 | 继续轮询 |
slow_down | 400 | 轮询过快 | 间隔加倍 |
expired_token | 400 | 设备码/授权码过期 | 终止,重新发起 |
invalid_grant | 400 | 授权码无效/已使用/跨客户端/redirect_uri 不匹配 | 终止,重新发起 |
too_many_requests | 429 | 触发限流 | 按 Retry-After 等待 |
server_error | 500 | 服务端异常 | 稍后重试 |
| 项 | 要求 |
|---|---|
| 传输 | 全程 HTTPS |
| 应用白名单 | client_id 必须已登记且启用 |
| redirect_uri 白名单(模式 B) | 必须精确匹配已登记地址 |
| PKCE(模式 B) | S256 强制,换码时校验 code_verifier |
| state(模式 B) | 必填回传,接入端负责校验防 CSRF |
| 授权码一次性 | 使用后即失效;10 分钟有效 |
| 凭证保管 | 禁止硬编码;使用操作系统凭据库或密钥管理服务 |
| 凭证泄露 | 立即联系平台吊销,引导用户重新授权 |
文档版本:v1.0(2026-09-15) 如有对接问题,请联系帮我吧技术支持。