docs: add OAuth deep dive

This commit is contained in:
Peter Steinberger
2026-01-08 09:29:29 +01:00
parent 615991a5da
commit 0b611fc354
10 changed files with 182 additions and 12 deletions

View File

@@ -166,7 +166,7 @@ Options:
- `--workspace <dir>`
- `--non-interactive`
- `--mode <local|remote>`
- `--auth-choice <oauth|openai-codex|antigravity|apiKey|minimax|skip>`
- `--auth-choice <oauth|claude-cli|openai-codex|codex-cli|antigravity|apiKey|minimax|skip>`
- `--anthropic-api-key <key>`
- `--gateway-port <port>`
- `--gateway-bind <loopback|lan|tailnet|auto>`
@@ -202,7 +202,7 @@ Options:
Manage chat provider accounts (WhatsApp/Telegram/Discord/Slack/Signal/iMessage).
Subcommands:
- `providers list`: show configured chat providers and auth profiles (Claude CLI + Codex CLI sync included).
- `providers list`: show configured chat providers and auth profiles (Claude Code + Codex CLI OAuth sync included).
- `providers status`: check gateway reachability and provider health (`--probe` to verify credentials; use `status --deep` for local-only probes).
- `providers add`: wizard-style setup when no flags are passed; flags switch to non-interactive mode.
- `providers remove`: disable by default; pass `--delete` to remove config entries without prompts.
@@ -227,6 +227,12 @@ Common options:
- `--no-usage`: skip provider usage/quota snapshots (OAuth/API-backed only).
- `--json`: output JSON (includes usage unless `--no-usage` is set).
OAuth sync sources:
- `~/.claude/.credentials.json``anthropic:claude-cli`
- `~/.codex/auth.json``openai-codex:codex-cli`
More detail: [/concepts/oauth](/concepts/oauth)
Examples:
```bash
clawdbot providers add --provider telegram --account alerts --name "Alerts Bot" --token $TELEGRAM_BOT_TOKEN

View File

@@ -21,6 +21,8 @@ Clawdbot uses **auth profiles** for both API keys and OAuth tokens.
- Config `auth.profiles` / `auth.order` are **metadata + routing only** (no secrets).
- Legacy import-only OAuth file: `~/.clawdbot/credentials/oauth.json` (imported into `auth-profiles.json` on first use).
More detail: [/concepts/oauth](/concepts/oauth)
Credential types:
- `type: "api_key"``{ provider, key }`
- `type: "oauth"``{ provider, access, refresh, expires, email? }` (+ `projectId`/`enterpriseUrl` for some providers)

133
docs/concepts/oauth.md Normal file
View File

@@ -0,0 +1,133 @@
---
summary: "OAuth in Clawdbot: token exchange, storage, CLI sync, and multi-account patterns"
read_when:
- You want to understand Clawdbot OAuth end-to-end
- You hit token invalidation / logout issues
- You want to reuse Claude Code / Codex CLI OAuth tokens
- You want multiple accounts or profile routing
---
# OAuth
Clawdbot supports “subscription auth” via OAuth for providers that offer it (notably **Anthropic (Claude Pro/Max)** and **OpenAI Codex (ChatGPT OAuth)**). This page explains:
- how the OAuth **token exchange** works (PKCE)
- where tokens are **stored** (and why)
- how we **reuse external CLI tokens** (Claude Code / Codex CLI)
- how to handle **multiple accounts** (profiles + per-session overrides)
## The token sink (why it exists)
OAuth providers commonly mint a **new refresh token** during login/refresh flows. Some providers (or OAuth clients) can invalidate older refresh tokens when a new one is issued for the same user/app.
Practical symptom:
- you log in via Clawdbot *and* via Claude Code / Codex CLI → one of them randomly gets “logged out” later
To reduce that, Clawdbot treats `auth-profiles.json` as a **token sink**:
- the runtime reads credentials from **one place**
- we can **sync in** credentials from external CLIs instead of doing a second login
- we can keep multiple profiles and route them deterministically
## Storage (where tokens live)
Secrets are stored **per-agent**:
- Auth profiles (OAuth + API keys): `~/.clawdbot/agents/<agentId>/agent/auth-profiles.json`
- Runtime cache (managed automatically; dont edit): `~/.clawdbot/agents/<agentId>/agent/auth.json`
Legacy import-only file (still supported, but not the main store):
- `~/.clawdbot/credentials/oauth.json` (imported into `auth-profiles.json` on first use)
All of the above also respect `$CLAWDBOT_STATE_DIR` (state dir override). Full reference: [/gateway/configuration](/gateway/configuration#auth-storage-oauth--api-keys)
## Reusing Claude Code / Codex CLI OAuth tokens (recommended)
If you already signed in with the external CLIs *on the gateway host*, Clawdbot can reuse those tokens without starting a separate OAuth flow:
- Claude Code: reads `~/.claude/.credentials.json` → profile `anthropic:claude-cli`
- Codex CLI: reads `~/.codex/auth.json` → profile `openai-codex:codex-cli`
Sync happens when Clawdbot loads the auth store (so it stays up-to-date when the CLIs refresh tokens).
How to verify:
```bash
clawdbot providers list
```
Or JSON:
```bash
clawdbot providers list --json
```
## OAuth exchange (how login works)
Clawdbots interactive login flows are implemented in `@mariozechner/pi-ai` and wired into the wizards/commands.
### Anthropic (Claude Pro/Max)
Flow shape (PKCE):
1) generate PKCE verifier/challenge
2) open `https://claude.ai/oauth/authorize?...`
3) user pastes `code#state`
4) exchange at `https://console.anthropic.com/v1/oauth/token`
5) store `{ access, refresh, expires }` under an auth profile
The wizard path is `clawdbot onboard` → auth choice `oauth` (Anthropic).
### OpenAI Codex (ChatGPT OAuth)
Flow shape (PKCE):
1) generate PKCE verifier/challenge + random `state`
2) open `https://auth.openai.com/oauth/authorize?...`
3) try to capture callback on `http://127.0.0.1:1455/auth/callback`
4) if callback cant bind (or youre remote/headless), paste the redirect URL/code
5) exchange at `https://auth.openai.com/oauth/token`
6) extract `accountId` from the access token and store `{ access, refresh, expires, accountId }`
Wizard path is `clawdbot onboard` → auth choice `openai-codex` (or `codex-cli` to reuse an existing Codex CLI login).
## Refresh + expiry
Profiles store an `expires` timestamp.
At runtime:
- if `expires` is in the future → use the stored access token
- if expired → refresh (under a file lock) and overwrite the stored credentials
See implementation: `src/agents/auth-profiles.ts`.
## Multiple accounts (profiles) + routing
Two patterns:
### 1) Preferred: separate agents
If you want “personal” and “work” to never interact, use isolated agents (separate sessions + credentials + workspace):
```bash
clawdbot agents add work
clawdbot agents add personal
```
Then configure auth per-agent (wizard) and route chats to the right agent.
### 2) Advanced: multiple profiles in one agent
`auth-profiles.json` supports multiple profile IDs for the same provider.
Pick which profile is used:
- globally via config ordering (`auth.order`)
- per-session via `/model ...@<profileId>`
Example (session override):
- `/model Opus@anthropic:work`
How to see what profile IDs exist:
- `clawdbot providers list --json` (shows `auth[]`)
Related docs:
- [/concepts/model-failover](/concepts/model-failover) (rotation + cooldown rules)
- [/tools/slash-commands](/tools/slash-commands) (command surface)

View File

@@ -508,6 +508,10 @@
{
"source": "/wizard",
"destination": "/start/wizard"
},
{
"source": "/oauth",
"destination": "/concepts/oauth"
}
],
"navigation": {
@@ -544,6 +548,7 @@
"concepts/agent",
"concepts/agent-loop",
"concepts/system-prompt",
"concepts/oauth",
"concepts/agent-workspace",
"concepts/multi-agent",
"concepts/compaction",

View File

@@ -116,6 +116,8 @@ Env var equivalent:
Clawdbot stores **per-agent** auth profiles (OAuth + API keys) in:
- `<agentDir>/auth-profiles.json` (default: `~/.clawdbot/agents/<agentId>/agent/auth-profiles.json`)
See also: [/concepts/oauth](/concepts/oauth)
Legacy OAuth imports:
- `~/.clawdbot/credentials/oauth.json` (or `$CLAWDBOT_STATE_DIR/credentials/oauth.json`)
@@ -131,6 +133,10 @@ Overrides:
On first use, Clawdbot imports `oauth.json` entries into `auth-profiles.json`.
Clawdbot also auto-syncs OAuth tokens from external CLIs into `auth-profiles.json` (when present on the gateway host):
- `~/.claude/.credentials.json` (Claude Code) → `anthropic:claude-cli`
- `~/.codex/auth.json` (Codex CLI) → `openai-codex:codex-cli`
### `auth`
Optional metadata for auth profiles. This does **not** store secrets; it maps

View File

@@ -339,6 +339,8 @@ Fix: either provide Google auth, or remove/avoid Google models in `agent.model.f
## Auth profiles: what they are and how to manage them
Related: [/concepts/oauth](/concepts/oauth) (OAuth flows, token storage, multi-account patterns, CLI sync)
### What is an auth profile?
An auth profile is a named credential record (OAuth or API key) tied to a provider. Profiles live in:

View File

@@ -54,6 +54,7 @@ Use these hubs to discover every page, including deep dives and reference docs t
- [Groups](https://docs.clawd.bot/concepts/groups)
- [Group messages](https://docs.clawd.bot/concepts/group-messages)
- [Model failover](https://docs.clawd.bot/concepts/model-failover)
- [OAuth](https://docs.clawd.bot/concepts/oauth)
## Providers + ingress

View File

@@ -32,6 +32,8 @@ Implementation note (2025-12-19): in local mode, the macOS app bundles the Gatew
This is the “bind Clawdbot to subscription auth” step. It is explicitly the **Anthropic (Claude Pro/Max)** or **OpenAI (ChatGPT/Codex)** OAuth flow, not a generic “login”.
More detail: [/concepts/oauth](/concepts/oauth)
### Recommended: OAuth (Anthropic)
The macOS app should:
@@ -165,15 +167,29 @@ On the gateway host, create `~/.clawdbot/credentials/oauth.json` with this exact
Set permissions: `chmod 600 ~/.clawdbot/credentials/oauth.json`
**Note:** Clawdbot auto-imports from legacy pi-coding-agent paths (`~/.pi/agent/oauth.json`, etc.) but this does NOT work with Claude Code credentials different file and format.
**Note:** Clawdbot can import from legacy pi-coding-agent paths (`~/.pi/agent/oauth.json`, etc.), but Claude Code/Codex CLI credentials live in different files.
### Using Claude Code credentials
### Using Claude Code + Codex CLI credentials (direct)
If Claude Code is installed on the gateway host, convert its credentials:
If these CLIs are installed on the **gateway host** and youve already signed in, Clawdbot auto-syncs their OAuth tokens into the per-agent auth profile store (`~/.clawdbot/agents/<agentId>/agent/auth-profiles.json`) on load:
- **Claude Code**: reads `~/.claude/.credentials.json` → profile `anthropic:claude-cli`
- **Codex CLI**: reads `~/.codex/auth.json` → profile `openai-codex:codex-cli`
Verification:
```bash
clawdbot providers list
```
### Fallback: convert Claude Code credentials into `oauth.json`
If you dont want to install Claude Code on the gateway host, you can still seed the legacy import file:
```bash
cat ~/.claude/.credentials.json | jq '{
anthropic: {
type: "oauth",
access: .claudeAiOauth.accessToken,
refresh: .claudeAiOauth.refreshToken,
expires: .claudeAiOauth.expiresAt
@@ -182,12 +198,6 @@ cat ~/.claude/.credentials.json | jq '{
chmod 600 ~/.clawdbot/credentials/oauth.json
```
| Claude Code field | Clawdbot field |
|-------------------|---------------|
| `accessToken` | `access` |
| `refreshToken` | `refresh` |
| `expiresAt` | `expires` |
## Workspace backup (recommended)
We suggest creating a **private GitHub repository** to back up the agent

View File

@@ -56,7 +56,9 @@ Tip: `--json` does **not** imply non-interactive mode. Use `--non-interactive` (
- Full reset (also removes workspace)
2) **Model/Auth**
- **Anthropic OAuth (Claude CLI)**: if `~/.claude/.credentials.json` exists, the wizard can reuse it.
- **Anthropic OAuth (recommended)**: browser flow; paste the `code#state`.
- **OpenAI Codex OAuth (Codex CLI)**: if `~/.codex/auth.json` exists, the wizard can reuse it.
- **OpenAI Codex OAuth**: browser flow; paste the `code#state`.
- Sets `agent.model` to `openai-codex/gpt-5.2` when model is unset or `openai/*`.
- **API key**: stores the key for you.
@@ -64,6 +66,7 @@ Tip: `--json` does **not** imply non-interactive mode. Use `--non-interactive` (
- **Skip**: no auth configured yet.
- Wizard runs a model check and warns if the configured model is unknown or missing auth.
- OAuth credentials live in `~/.clawdbot/credentials/oauth.json`; auth profiles live in `~/.clawdbot/agents/<agentId>/agent/auth-profiles.json` (API keys + OAuth).
- More detail: [/concepts/oauth](/concepts/oauth)
3) **Workspace**
- Default `~/clawd` (configurable).

View File

@@ -232,7 +232,7 @@ export function buildProgram() {
.option("--mode <mode>", "Wizard mode: local|remote")
.option(
"--auth-choice <choice>",
"Auth: oauth|openai-codex|antigravity|apiKey|minimax|skip",
"Auth: oauth|claude-cli|openai-codex|codex-cli|antigravity|apiKey|minimax|skip",
)
.option("--anthropic-api-key <key>", "Anthropic API key")
.option("--gateway-port <port>", "Gateway port")
@@ -259,7 +259,9 @@ export function buildProgram() {
mode: opts.mode as "local" | "remote" | undefined,
authChoice: opts.authChoice as
| "oauth"
| "claude-cli"
| "openai-codex"
| "codex-cli"
| "antigravity"
| "apiKey"
| "minimax"