Skip to content

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",...}                              │                              │
     └                            └                            └                              ┘

2. 各步骤详细请求/响应

Step 1: 发起登录 POST /auth/login/start

请求

POST http://localhost:13456/auth/login/start
Content-Type: application/json

{"open_browser": false}

响应 HTTP 200

Content-Type: application/json

{
  "login_id": "c0331f31-8344-4e11-8d62-459c9345a396",
  "url": "https://acs.atomgit.com/s/787fbe78",
  "expires_in_seconds": 600
}
字段说明
login_idUUID,标识本次登录会话
url用户需要打开的 OAuth 授权 URL(短链接,重定向到 AtomGit OAuth)
expires_in_seconds登录会话有效时间(600 秒 = 10 分钟)

注意: urlacs.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

{}

响应(成功) 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"
  }
}

响应(未完成) HTTP 200

json
{
  "login_pending": true,
  "message": "Login still pending. Poll /auth/login/:login_id/poll until authorized."
}

响应(过期) HTTP 200

json
{
  "error": "Login session not found or expired"
}
字段说明
status"authorized" 表示授权成功
login_pendingtrue 时说明用户还没完成授权
user.idAtomGit 用户 ID
user.email用户邮箱(可能被平台隐藏)

Step 3: 检查认证状态 GET /auth/status

请求

GET http://localhost:13456/auth/status

响应 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
  }
}
字段说明
logged_in是否已登录
auth_path本地 token 文件路径
token.expires_inToken 过期时间(秒),约 7 天
token.has_refresh_token是否有 refresh token

Step 4: 领取 CodingPlan POST /codingplan/setup

请求

POST http://localhost:13456/codingplan/setup
Content-Type: application/json

{}

响应 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": ""}
  }
}
字段说明
success是否领取成功
default_provider默认 Provider 名称
providers[].base_urlLLM 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"
}

请求参数

参数类型说明
messagestring用户消息文本
streambool是否流式返回
providerstringProvider 名称(可选,默认使用 default_provider)
systemstring系统提示词(可选,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"}
: bye

SSE 事件类型

事件字段说明
reasoningcontent模型推理过程(DeepSeek 特有)
textcontent输出文本片段
tokensprompt, completion, totalToken 用量统计
tool_startid, name, arguments工具调用开始
tool_outputchunk工具输出块
tool_resultid, name, output, success, duration_ms工具调用结果
errormessage错误信息
donesession_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/..."

~/.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 = true

~/.atomcode/codingplan_sync.json

json
{
  "last_sync_unix_secs": 1781279383
}

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    │
└──────────────┘                └────────────────┘              └────────────┘
  • 代理层将 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 完整索引

端点方法请求体说明
/healthGET健康检查 {"status":"ok","version":"4.25.3","binary_hash":"..."}
/auth/login/startPOST{"open_browser": bool}发起 OAuth 登录
/auth/login/:id/pollPOST{}轮询登录结果
/auth/login/:idDELETE取消登录
/auth/statusGET检查登录和 token 状态
/auth/logoutPOST登出(⚠️ 会删除 auth.toml)
/codingplan/setupPOST{}领取 CodingPlan
/chatPOST{"message","stream","provider","system","session_id"}发送 Chat (SSE)
/modelsGET列出可用模型
/providersGET列出 Provider
/configGET获取配置(含 provider 详情)
/config/reloadPOST重新加载配置
/skillsGET列出技能(内置约 47 个技能)
/sessionsGET列出所有会话
/sessions/searchGET?q=keyword搜索会话
/projectsGET列出历史项目
/projects/:hash/sessionsGET/POST项目会话管理
/cdPOST{"path":"..."}切换工作目录
/providers/:name/defaultPOST设置默认 Provider
/providers/:name/thinkingPATCH配置思考模式
/mcp/statusGETMCP 状态(返回空服务器列表)
/mcp/reloadPOST重载 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      # 会话完整消息记录

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/..."

⚠️ /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": []
}
  • 消息角色:UserAssistantTool
  • 内容类型: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": []
  }
}

7.5 调用汇总日志 (calls.log)

2026-06-17_17-30-22_832  deepseek-v4-flash  step=0  msgs=4/6391tok  →  1528ms  tools=0 text_only
字段说明
timestamp调用时间
model使用模型
step步数
msgs=N/Mtok消息数 / token 数
→ Nms响应时长
tools=N [name]工具调用次数和名称
text_only纯文本响应标记

8. Daemon 运行环境

Daemon 进程直接继承用户的 shell 环境变量。关键环境变量:

变量说明
ANTHROPIC_API_KEYe5e86d37-...从父进程 Claude Code 继承,并非 daemon 自身使用
NODE_TLS_REJECT_UNAUTHORIZED0跳过 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."

9.2 OAuth 授权完成后

浏览器显示 Authorization Successful + 用户信息,设备上 daemon 通过轮询 /auth/login/:id/poll 捕获 token,需要轮询和授权在同一个 login_id 上完成——生成新 login_id 会导致旧链接立即失效。


10. 关键发现总结(更新版)

  1. OAuth 流程不是标准 OAuth 2.0:使用短链接 + 轮询机制,没有 PKCE
  2. CodingPlan 免费额度:Lite 计划,30 天有效期,有 token 量窗口限制
  3. API key 不落盘:由 daemon 内部通过 OAuth token 派生管理,不暴露
  4. LLM API 兼容 OpenAIllm-api.atomgit.com/v1 使用 OpenAI API 格式
  5. Daemon 是唯一入口:所有 AI 能力必须通过 daemon 的 /chat 端点调用
  6. Token 有效期 7 天:有 refresh_token 可续期
  7. SSE 事件类型丰富:10 种事件类型,支持 reasoning、tool 等高级功能
  8. 短链接权威性:每个 login_id 对应唯一短链接,生成新链接后旧链接立即过期
  9. 完整会话持久化:每次对话的完整消息历史(含 tool_calls、reasoning)写入磁盘 session JSON
  10. LLM 调用日志:每次调用记录到 datalog,含 token 估算、时长、工具使用情况
  11. Daemon 版本更新:从 v4.25.1 自动升级到 v4.25.3(有 binary_hash 追踪),说明有自动更新机制
  12. 登出行为/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.toml

基于 VitePress 构建 · AtomCode v4.25.3 逆向工程分析文档