AtomCode 授权协议深度分析补充 — 授权码 + PKCE + MCP OAuth 动态注册
日期: 2026-06-24 | 基于二进制静态分析和运行抓包 补充
AUTHORIZATION_PROTOCOL.md中未覆盖的 OAuth 深层细节
1. 授权流程总结
AtomCode 支持 3 种授权模式:
| 模式 | 适用场景 | 安全级别 | 是否已覆盖 |
|---|---|---|---|
| ACS OAuth 轮询 | AtomGit 平台登录 / CodingPlan | 高 | ✅ 已在 AUTHORIZATION_PROTOCOL.md 覆盖 |
| MCP OAuth 授权码 + PKCE | MCP 服务器远程认证 | 最高 | ❌ 本轮新增 |
| GitHub OAuth 授权码 | GitHub MCP 服务器集成 | 高 | ❌ 本轮新增 |
2. MCP OAuth 授权码 + PKCE 完整流程
这是 AtomCode 中最安全的授权协议,使用标准的 OAuth 2.0 Authorization Code Grant + PKCE (S256)。
2.1 核心端点
从二进制中提取的 OAuth 授权服务器元数据:
rust
struct AuthorizationServerMetadata {
// 5 个字段
authorization_endpoint: String, // 授权端点 (用户浏览器)
token_endpoint: String, // Token 交换端点
registration_endpoint: String, // 动态客户端注册端点 (RFC 7591)
// 2 个额外字段
}2.2 完整授权码流程
Step 1: 发现授权服务器元数据
GET {authorization_server}/.well-known/oauth-authorization-server
→ 解析 AuthorizationServerMetadata
| "Failed to fetch MCP OAuth resource metadata from {}"
| "Failed to parse MCP OAuth resource metadata from {}"
Step 2: 动态客户端注册(如果支持)
POST {registration_endpoint}
Body: {
"client_name": "...",
"redirect_uris": ["http://127.0.0.1:{port}/callback"],
"grant_types": ["authorization_code"],
"response_types": ["code"],
"token_endpoint_auth_method": "none" // 或 "client_secret_basic"
}
→ 返回 client_id + client_secret
| "MCP OAuth dynamic client registration failed: HTTP {}"
| "Failed to dynamically register MCP OAuth client"
|
| ⚠ 如果不支持动态注册:
| "MCP OAuth requires a pre-registered client_id because
| the authorization server does not support dynamic
| client registration (RFC 7591). Add a pre-registered
| client_id to auth.client_id in your .mcp.json..."
Step 3: PKCE 挑战生成
code_verifier = crypto_random_string(43-128 chars)
code_challenge = base64url(sha256(code_verifier)) // S256 方法
Step 4: 打开浏览器进行授权
GET {authorization_endpoint}?
response_type=authorization_code&
client_id={client_id}&
redirect_uri=http://127.0.0.1:{port}/callback&
code_challenge={base64url_sha256(code_verifier)}&
code_challenge_method=S256&
scope={scope}&
state={anti_csrf_token}
用户浏览器打开授权页面
→ 用户登录并授权
→ 浏览器重定向到 redirect_uri?code={auth_code}&state={state}
Step 5: 绑定本地 OAuth 回调监听
| "Failed to bind local OAuth callback listener"
在本地 127.0.0.1 启动临时 HTTP 服务器监听回调
Step 6: 接收回调
| "Failed to accept OAuth callback"
| "OAuth callback did not include code"
| "OAuth callback did not include state"
| "Invalid OAuth callback URL"
| "Invalid OAuth callback request"
✓ 验证 state (anti-CSRF)
✓ 提取 authorization_code
Step 7: 交换 Token
POST {token_endpoint}
Body: {
"grant_type": "authorization_code",
"code": "{auth_code}",
"code_verifier": "{code_verifier}",
"redirect_uri": "http://127.0.0.1:{port}/callback",
"client_id": "{client_id}"
}
→ 返回 TokenResponse
| "Failed to exchange MCP OAuth code"
| "Failed to parse MCP OAuth token response"
Step 8: 存储 Token
存储为 McpOAuthToken (11 字段)2.3 MCP OAuth Token 存储结构
rust
struct McpOAuthToken {
// 11 个元素 — 最复杂的认证相关结构体
access_token: String,
token_type: String, // Bearer
expires_in: Option<u64>,
refresh_token: Option<String>,
scope: Option<String>,
client_id: Option<String>,
client_secret: Option<String>,
client_secret_env: Option<String>, // 环境变量引用
// ... 3 个额外字段
}3. GitHub MCP OAuth 集成
3.1 GitHub MCP 服务器认证
GitHub MCP 有专门的处理逻辑:
rust
// GitHub MCP 的特殊端点
"https://api.githubcopilot.com/mcp/"
"https://github.com/login/oauth/authorize" // GitHub OAuth 授权
"https://github.com/login/oauth/access_token" // Token 交换
// 特定错误处理
"GitHub MCP OAuth requires --client-secret-env or auth.client_secret_env in mcp.json"
"GitHub OAuth client id is required"
"Failed to exchange GitHub OAuth code"
"Failed to parse GitHub OAuth token response"3.2 GitHub OAuth 流程
环境变量或配置中提供 client_id 和 client_secret:
ATOMCODE_GITHUB_MCP_CLIENT_ID (环境变量)
或 auth.client_secret_env (mcp.json 配置)
→ https://github.com/login/oauth/authorize 发起授权
→ 用户 GitHub 授权页面
→ 回调 → code 交换
→ POST https://github.com/login/oauth/access_token
→ 获取 GitHub Copilot MCP 的 access_token4. ACS 平台 OAuth 流程(补充 AUTHORIZATION_PROTOCOL.md)
4.1 平台登录完整 API
从二进制中提取的平台认证结构体:
rust
struct PlatformLoginResponse {
auth_url: String, // 授权 URL
login_id: String, // 登录会话 ID
}
struct PlatformCheckResponse {
logged_in: bool, // 是否已登录
}
struct PlatformTokenResponse {
// 5 个元素
access_token: String,
token_type: String,
expires_in: u64,
refresh_token: Option<String>,
scope: Option<String>,
}
struct PlatformUserInfo {
// 5 个元素
id: String,
login: String,
name: String,
avatar: String,
// 1 个额外字段
}4.2 Token 自动刷新
rust
// 刷新逻辑
"OAuth token is expired and has no refresh token"
"OAuth token is expired; run 'atomcode mcp login <server>'"
"Token expired"
"Token refresh failed"
struct RefreshedAuth {
access_token: String,
token_type: String,
expires_in: u64,
refresh_token: Option<String>,
// 1 个额外字段
}
struct RefreshedUser {
id: String,
login: String,
name: String,
avatar: String,
// 1 个额外字段
}5. ACS 短链接轮询登录(补充细节)
AUTHORIZATION_PROTOCOL.md 已覆盖了轮询流程,补充二进制中发现的错误处理字符串:
rust
// 平台认证相关
"please use /login first"
"Login session not found or expired"
"Login still pending. Poll /auth/login/:login_id/poll until authorized."
// 平台服务器配置
ATOMCODE_PLATFORM_SERVER = "https://acs.atomgit.com"
"&force_login=true" // 短链接重定向时强制登录参数MCP OAuth 的额外配置
mcp.json 中的认证配置字段:
json
{
"auth": {
"client_id": "xxx", // 预注册的 client_id
"client_secret_env": "MY_SECRET", // 引用环境变量
"authorization_servers": ["..."] // 授权服务器元数据 URL
}
}6. 授权相关文件
~/.atomcode/
├── auth.toml → OAuth token 存储
│ access_token / refresh_token / token_type / expires_in / created_at
│ [user] id / login / name / email / avatar_url
│
├── .mcp.json → MCP 服务器配置(含 OAuth 字段)
│
└── sessions/
└── ... → 会话文件(含 OAuth 状态)7. 总结
| # | 授权机制 | 协议 | 安全性 | 已覆盖 |
|---|---|---|---|---|
| 1 | ACS 平台 OAuth + 轮询 (AtomGit 登录) | 自定义 | 中 | ✅ 已有 + 本轮补充 |
| 2 | MCP OAuth 授权码 + PKCE + 动态客户端注册 | RFC 6749 + RFC 7636 + RFC 7591 | 最高 | ✅ 本轮新增 |
| 3 | GitHub MCP OAuth (Copilot 集成) | 授权码 + client_secret | 高 | ✅ 本轮新增 |
| 4 | Token 自动刷新 | Refresh Token | 中 | ✅ 本轮补充 |
总结:AtomCode 完整实现了 OAuth 2.0 授权码授权流 + PKCE 扩展(S256)—— 这是目前移动端和单页应用推荐的最安全认证模式。 同时支持 RFC 7591 动态客户端注册和传统的预注册 client_id 方式。
本报告由持续分析生成 — 授权深度分析补充