AtomCode OAuth 授权协议 & 全链路分析报告
基于 v4.25.1 实际运行时抓包分析 2026-06-12
1. 总体流程
┌─────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌───────────────────┐
│ 用户 │ │ Daemon │ │ acs.atomgit.com │ │ api.gitcode.com │
│ (curl/ │ │ localhost:13456 │ │ (短链接 + OAuth) │ │ (CodingPlan API) │
│ WebUI) │ │ │ │ │ │ │
└────┬────┘ └────────┬───────────┘ └────────┬──────────┘ └────────┬──────────┘
│ │ │ │
│ 1. POST /auth/login/start │ │ │
│ {"open_browser": false} │ │ │
├─────────────────────────► │ │ │
│ │ │ │
│ ◄── 200 OK │ │ │
│ { │ │ │
│ "login_id": "uuid", │ │ │
│ "url": "https:// │ │ │
│ acs.atomgit.com/s/X", │ │ │
│ "expires_in_seconds": │ │ │
│ 600 │ │ │
│ } │ │ │
│ │ │ │
│ 2. 用户浏览器打开 url → OAuth 授权 │ │
├────────────────────────────┼──────────────────────────► │
│ │ │ │
│ 3. POST /auth/login/:id/poll │ │ │
│ (每 2-5 秒轮询,最长 600 秒) │ │ │
├─────────────────────────► │ │ │
│ │ │ │
│ ◄── 200 OK │ │ │
│ { │ │ │
│ "status":"authorized", │ │ │
│ "user": { │ │ │
│ "id":"...", │ │ │
│ "username":"...", │ │ │
│ "name":"...", │ │ │
│ "email":"...", │ │ │
│ "avatar_url":"..." │ │ │
│ } │ │ │
│ } │ │ │
│ │ │ │
│ 4. GET /auth/status │ │ │
├─────────────────────────► │ │ │
│ ◄── 200 OK ← 完整的 token/user 信息 │ │
│ │ │ │
│ 5. POST /codingplan/setup │ │ │
│ (领取 CodingPlan 额度) │ │ │
├─────────────────────────► ├──── claim-v2 ──────────► │
│ ├──── status-v2 ─────────► │
│ ├──── models-v2 ─────────► │
│ ◄── 200 OK │ │ │
│ { success:true, │ │ │
│ providers: [...], │ │ │
│ default_provider: "...", │ │ │
│ steps: {...} } │ │ │
│ │ │ │
│ 6. POST /chat │ │ │
│ {"message":"...", │ │ │
│ "stream":true, │ │ │
│ "provider":"..."} │ │ │
├─────────────────────────► ├── llm-api.atomgit.com ──► │
│ ◄── SSE 流 (text/event-stream) │ │
│ data: {"type":"reasoning",...} │ │
│ data: {"type":"text",...} │ │
│ data: {"type":"tokens",...} │ │
│ data: {"type":"done",...} │ │
└ └ └ ┘1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
2. 各步骤详细请求/响应
Step 1: 发起登录 POST /auth/login/start
请求
POST http://localhost:13456/auth/login/start
Content-Type: application/json
{"open_browser": false}1
2
3
4
2
3
4
响应 HTTP 200
Content-Type: application/json
{
"login_id": "c0331f31-8344-4e11-8d62-459c9345a396",
"url": "https://acs.atomgit.com/s/787fbe78",
"expires_in_seconds": 600
}1
2
3
4
5
6
7
2
3
4
5
6
7
| 字段 | 说明 |
|---|---|
login_id | UUID,标识本次登录会话 |
url | 用户需要打开的 OAuth 授权 URL(短链接,重定向到 AtomGit OAuth) |
expires_in_seconds | 登录会话有效时间(600 秒 = 10 分钟) |
注意:
url是acs.atomgit.com/s/XXX短链接,浏览器打开后会 302 重定向到 AtomGit 的 OAuth 授权页面。授权完成后,页面会重定向到带?token=xxx的 URL,WebUI 从中提取 token。
Step 2: 轮询登录结果 POST /auth/login/:login_id/poll
请求
POST http://localhost:13456/auth/login/c0331f31-8344-4e11-8d62-459c9345a396/poll
Content-Type: application/json
{}1
2
3
4
2
3
4
响应(成功) HTTP 200
Content-Type: application/json
{
"status": "authorized",
"user": {
"id": "69d3ed86485d100d1253dd29",
"username": "CC11001100",
"name": "CC11001100",
"email": "CC11001100@qq.com",
"avatar_url": "https://cdn-img.gitcode.com/ac/ee/40a02c61ee9f9ab5ab163d69fa9e8fa92ad2b6de4219aaa515f0b7a4e628f05f.jpg"
}
}1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
响应(未完成) HTTP 200
json
{
"login_pending": true,
"message": "Login still pending. Poll /auth/login/:login_id/poll until authorized."
}1
2
3
4
2
3
4
响应(过期) HTTP 200
json
{
"error": "Login session not found or expired"
}1
2
3
2
3
| 字段 | 说明 |
|---|---|
status | "authorized" 表示授权成功 |
login_pending | 为 true 时说明用户还没完成授权 |
user.id | AtomGit 用户 ID |
user.email | 用户邮箱(可能被平台隐藏) |
Step 3: 检查认证状态 GET /auth/status
请求
GET http://localhost:13456/auth/status1
响应 HTTP 200
Content-Type: application/json
{
"logged_in": true,
"auth_path": "/home/cc11001100/.atomcode/auth.toml",
"user": {
"id": "69d3ed86485d100d1253dd29",
"username": "CC11001100",
"name": "CC11001100",
"email": "CC11001100@qq.com",
"avatar_url": "https://cdn-img.gitcode.com/ac/ee/40a02c61ee9f9ab5ab163d69fa9e8fa92ad2b6de4219aaa515f0b7a4e628f05f.jpg"
},
"token": {
"token_type": "Bearer",
"expires_in": 604799,
"created_at": 1781279361,
"has_refresh_token": true
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| 字段 | 说明 |
|---|---|
logged_in | 是否已登录 |
auth_path | 本地 token 文件路径 |
token.expires_in | Token 过期时间(秒),约 7 天 |
token.has_refresh_token | 是否有 refresh token |
Step 4: 领取 CodingPlan POST /codingplan/setup
请求
POST http://localhost:13456/codingplan/setup
Content-Type: application/json
{}1
2
3
4
2
3
4
响应 HTTP 200
Content-Type: application/json
{
"success": true,
"report_text": " AtomCode CodingPlan setup:\n\n ✓ already logged in as CC11001100\n ✓ CodingPlan Lite active\n ✓ Added 2 providers:\n ...\n",
"default_provider": "AtomGit-deepseek-v4-flash",
"providers": [
{
"name": "AtomGit-deepseek-v4-flash",
"type": "openai",
"model": "deepseek-v4-flash",
"base_url": "https://llm-api.atomgit.com/v1",
"has_api_key": false,
"is_default": true,
"context_window": 1000000,
"max_tokens": null,
"thinking_enabled": null,
"thinking_budget": null,
"thinking_type": null,
"thinking_keep": null,
"reasoning_history": null,
"reasoning_effort": null,
"skip_tls_verify": false,
"ephemeral": false
},
{
"name": "AtomGit-Qwen-Qwen3-VL-8B-Instruct",
"type": "openai",
"model": "Qwen/Qwen3-VL-8B-Instruct",
"base_url": "https://llm-api.atomgit.com/v1",
"has_api_key": false,
"is_default": false,
"context_window": 64000,
...
}
],
"steps": {
"login": {"status": "skipped", "message": "already logged in as CC11001100"},
"claim": {"status": "ok", "message": ""},
"models": {"status": "ok", "message": ""},
"status": {"status": "ok", "message": ""}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| 字段 | 说明 |
|---|---|
success | 是否领取成功 |
default_provider | 默认 Provider 名称 |
providers[].base_url | LLM API 地址:https://llm-api.atomgit.com/v1 |
providers[].has_api_key | ⚡ 始终为 false — API key 由 daemon 内部管理,不暴露 |
steps.claim.status | "ok" 表示领取成功 |
report_text | 用户可读的报告文本 |
Step 5: 发送 Chat POST /chat (SSE Streaming)
请求
POST http://localhost:13456/chat
Content-Type: application/json
Accept: text/event-stream
{
"message": "回复一句话:你好",
"stream": true,
"provider": "AtomGit-deepseek-v4-flash"
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
请求参数
| 参数 | 类型 | 说明 |
|---|---|---|
message | string | 用户消息文本 |
stream | bool | 是否流式返回 |
provider | string | Provider 名称(可选,默认使用 default_provider) |
system | string | 系统提示词(可选,daemon 会自动注入默认的) |
响应 HTTP 200
Content-Type: text/event-stream
Cache-Control: no-cache
Transfer-Encoding: chunked
data: {"type":"reasoning","content":"The user wants..."}
data: {"type":"text","content":"你好!"}
data: {"type":"text","content":"有什么"}
data: {"type":"text","content":"可以"}
data: {"type":"text","content":"帮你"}
data: {"type":"tokens","prompt":8700,"completion":31,"total":8731}
data: {"type":"text","content":"吗?😊"}
data: {"type":"done","tokens":8731,"tool_calls":0,"session_id":"ea21aa73-52cd-426c-84d4-7ae9699ab955"}
: bye1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
SSE 事件类型
| 事件 | 字段 | 说明 |
|---|---|---|
reasoning | content | 模型推理过程(DeepSeek 特有) |
text | content | 输出文本片段 |
tokens | prompt, completion, total | Token 用量统计 |
tool_start | id, name, arguments | 工具调用开始 |
tool_output | chunk | 工具输出块 |
tool_result | id, name, output, success, duration_ms | 工具调用结果 |
error | message | 错误信息 |
done | session_id, tokens, tool_calls | 生成完成 |
stopped | (none) | 用户停止 |
3. 本地文件存储
~/.atomcode/auth.toml
toml
access_token = "1vQx477GWsCK-DQevteszmr3"
refresh_token = "416a389eb4624a43ba93f1f278f86887"
token_type = "Bearer"
expires_in = 604799
created_at = 1781279361
[user]
id = "69d3ed86485d100d1253dd29"
username = "CC11001100"
name = "CC11001100"
email = "CC11001100@qq.com"
avatar_url = "https://cdn-img.gitcode.com/..."1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
~/.atomcode/config.toml (核心配置)
toml
default_provider = "AtomGit-deepseek-v4-flash"
auto_update = true
auto_commit = false
[providers.AtomGit-deepseek-v4-flash]
type = "openai"
model = "deepseek-v4-flash"
base_url = "https://llm-api.atomgit.com/v1"
context_window = 1000000
[providers.AtomGit-Qwen-Qwen3-VL-8B-Instruct]
type = "openai"
model = "Qwen/Qwen3-VL-8B-Instruct"
base_url = "https://llm-api.atomgit.com/v1"
context_window = 64000
[lsp]
enabled = false
# ...
[ui]
theme = "auto"
[plugin]
auto_install_default_skills = true
auto_update_marketplaces = true1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
~/.atomcode/codingplan_sync.json
json
{
"last_sync_unix_secs": 1781279383
}1
2
3
2
3
4. API Key 管理机制
核心发现:API key 不由 config.toml 管理,而是由 daemon 进程内部持有。
| 存储位置 | 包含 API key? | 访问方式 |
|---|---|---|
config.toml | ❌ 不包含 | 直接读文件 |
auth.toml | ❌ 只有 OAuth token | 直接读文件 |
codingplan_sync.json | ❌ 只有时间戳 | 直接读文件 |
| Daemon 进程内存 | ✅ 有 | 通过 daemon API 间接使用 |
| Daemon 环境变量 | ✅ 有可能 | ANTHROPIC_API_KEY 可能是 |
这意味着: 无法直接通过文件获取 CodingPlan API key。必须通过 daemon 的 /chat 端点来使用 AI 能力。
5. 反向代理方案
基于以上分析,推荐以下两种方案:
方案 A:通过 Daemon /chat 代理(推荐)
┌──────────────┐ OpenAI API ┌────────────────┐ POST /chat ┌────────────┐
│ Cline/Codex │ ────────────▶ │ proxy.py │ ──────────▶ │ Daemon │
│ (OpenAI SDK) │ ◀──────────── │ (:8080/v1) │ ◀────────── │ :13456 │
└──────────────┘ └────────────────┘ └────────────┘1
2
3
4
2
3
4
- 代理层将 OpenAI
/v1/chat/completions→ 转换为 Daemon/chat - 无需获取 API key(daemon 内部管理)
- 缺点:daemon 必须一直在后台运行
方案 B:直接调用 llm-api.atomgit.com
- 需要从 daemon进程内存或环境变量中提取 CodingPlan API key
- 直接向
https://llm-api.atomgit.com/v1发 OpenAI 兼容请求 - 优点:无需 daemon 在后台
- 缺点:API key 提取方式不可靠
6. Daemon REST API 完整索引
| 端点 | 方法 | 请求体 | 说明 |
|---|---|---|---|
/health | GET | — | 健康检查 {"status":"ok","version":"4.25.3","binary_hash":"..."} |
/auth/login/start | POST | {"open_browser": bool} | 发起 OAuth 登录 |
/auth/login/:id/poll | POST | {} | 轮询登录结果 |
/auth/login/:id | DELETE | — | 取消登录 |
/auth/status | GET | — | 检查登录和 token 状态 |
/auth/logout | POST | — | 登出(⚠️ 会删除 auth.toml) |
/codingplan/setup | POST | {} | 领取 CodingPlan |
/chat | POST | {"message","stream","provider","system","session_id"} | 发送 Chat (SSE) |
/models | GET | — | 列出可用模型 |
/providers | GET | — | 列出 Provider |
/config | GET | — | 获取配置(含 provider 详情) |
/config/reload | POST | — | 重新加载配置 |
/skills | GET | — | 列出技能(内置约 47 个技能) |
/sessions | GET | — | 列出所有会话 |
/sessions/search | GET | ?q=keyword | 搜索会话 |
/projects | GET | — | 列出历史项目 |
/projects/:hash/sessions | GET/POST | — | 项目会话管理 |
/cd | POST | {"path":"..."} | 切换工作目录 |
/providers/:name/default | POST | — | 设置默认 Provider |
/providers/:name/thinking | PATCH | — | 配置思考模式 |
/mcp/status | GET | — | MCP 状态(返回空服务器列表) |
/mcp/reload | POST | — | 重载 MCP |
7. 本地文件系统深入分析
7.1 ~/.atomcode/ 目录完整结构
~/.atomcode/
├── auth.toml # OAuth token 存储
├── config.toml # 核心配置(provider、UI、datalog 等)
├── codingplan_sync.json # CodingPlan 同步时间戳
├── history # 历史记录(当前为空)
├── recent_dirs.txt # 最近工作目录
├── stderr.log # 运行日志(session start 记录)
├── datalog/
│ └── <project>-<hash>/
│ └── llm/
│ ├── <timestamp>.json # 每次 LLM 调用的完整请求/响应
│ └── calls.log # 调用汇总表
└── sessions/
└── <project_hash>/
└── <session_id>.json # 会话完整消息记录1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
7.2 auth.toml (OAuth 凭证)
toml
access_token = "Rcg91cwHsKmcTyobro7eGHCt"
refresh_token = "15c3ca2fbb814beba0f497ee1d1a21ca"
token_type = "Bearer"
expires_in = 601397 # 约 7 天
created_at = 1781981437
[user]
id = "69d3ed86485d100d1253dd29"
username = "CC11001100"
name = "CC11001100"
email = "CC11001100@qq.com"
avatar_url = "https://cdn-img.gitcode.com/..."1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
⚠️
/auth/logout会删除此文件。登出后必须重新走完整的 OAuth 流程。
7.3 Session 文件结构 (JSON)
{
"id": "uuid",
"name": "用户消息截取",
"working_dir": "/path/to/project",
"created_at": timestamp,
"updated_at": timestamp,
"messages": [
{
"role": "User",
"content": { "Text": "用户消息" }
},
{
"role": "Assistant",
"content": {
"AssistantWithToolCalls": {
"text": "助手回复",
"tool_calls": [],
"reasoning_content": "推理过程内容"
}
}
}
],
"turn_stats": [],
"cold_summaries": []
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- 消息角色:
User、Assistant、Tool - 内容类型:
Text(纯文本)、AssistantWithToolCalls(含工具调用的回复) - 每条 session 可包含完整多轮对话历史
7.4 LLM 调用日志 (datalog/)
每次 LLM 调用记录为一个 JSON 文件:
{
"context_window": 1000000,
"model": "deepseek-v4-flash",
"session_id": "uuid",
"step": 0,
"timestamp": "2026-06-12T15:51:05",
"request": {
"estimated_tokens": 6332,
"message_count": 2,
"messages": [...], // 完整请求消息(含 system prompt、工具列表)
"tool_count": 0,
"tools": [...] // 可用工具列表
},
"response": {
"duration_ms": 2023,
"reasoning_content": "...",
"text": "助手回复内容",
"tool_calls": []
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
7.5 调用汇总日志 (calls.log)
2026-06-17_17-30-22_832 deepseek-v4-flash step=0 msgs=4/6391tok → 1528ms tools=0 text_only1
| 字段 | 说明 |
|---|---|
timestamp | 调用时间 |
model | 使用模型 |
step | 步数 |
msgs=N/Mtok | 消息数 / token 数 |
→ Nms | 响应时长 |
tools=N [name] | 工具调用次数和名称 |
text_only | 纯文本响应标记 |
8. Daemon 运行环境
Daemon 进程直接继承用户的 shell 环境变量。关键环境变量:
| 变量 | 值 | 说明 |
|---|---|---|
ANTHROPIC_API_KEY | e5e86d37-... | 从父进程 Claude Code 继承,并非 daemon 自身使用 |
NODE_TLS_REJECT_UNAUTHORIZED | 0 | 跳过 TLS 验证(仅开发/测试环境) |
ATOMCODE_TELEMETRY | 未设置 | 默认遥测开启,设为 0 禁用 |
Daemon 自身不依赖特殊环境变量运行。CodingPlan 的 API key 由 daemon 内部通过 OAuth token 派生/管理,不暴露到环境变量或文件中。
9. 短链接与 OAuth 机制深入分析
9.1 短链接生命周期
用户请求 POST /auth/login/start
→ daemon 返回短链接 https://acs.atomgit.com/s/XXXXXXXX
→ 该链接有效期 600 秒(10 分钟)
→ 过期后访问返回 HTTP 410 Gone
→ 页面显示 "This login link has expired. Please request a new one."1
2
3
4
5
2
3
4
5
9.2 OAuth 授权完成后
浏览器显示 Authorization Successful + 用户信息,设备上 daemon 通过轮询 /auth/login/:id/poll 捕获 token,需要轮询和授权在同一个 login_id 上完成——生成新 login_id 会导致旧链接立即失效。
10. 关键发现总结(更新版)
- OAuth 流程不是标准 OAuth 2.0:使用短链接 + 轮询机制,没有 PKCE
- CodingPlan 免费额度:Lite 计划,30 天有效期,有 token 量窗口限制
- API key 不落盘:由 daemon 内部通过 OAuth token 派生管理,不暴露
- LLM API 兼容 OpenAI:
llm-api.atomgit.com/v1使用 OpenAI API 格式 - Daemon 是唯一入口:所有 AI 能力必须通过 daemon 的
/chat端点调用 - Token 有效期 7 天:有 refresh_token 可续期
- SSE 事件类型丰富:10 种事件类型,支持 reasoning、tool 等高级功能
- 短链接权威性:每个 login_id 对应唯一短链接,生成新链接后旧链接立即过期
- 完整会话持久化:每次对话的完整消息历史(含 tool_calls、reasoning)写入磁盘 session JSON
- LLM 调用日志:每次调用记录到 datalog,含 token 估算、时长、工具使用情况
- Daemon 版本更新:从 v4.25.1 自动升级到 v4.25.3(有 binary_hash 追踪),说明有自动更新机制
- 登出行为:
/auth/logout删除 auth.toml,需重新走完整 OAuth
逆向命令索引
bash
# 提取登录端点
strings atomcode.bin.bak | grep -E "/auth/login|/auth/token|/auth/status|/auth/logout" | sort -u
# 提取 token 存储
strings atomcode.bin.bak | grep -E "auth\.toml|refresh_token" | sort -u
# 运行时查看 auth.toml
cat ~/.atomcode/auth.toml1
2
3
4
5
6
7
8
2
3
4
5
6
7
8