docs: add OAuth deep dive
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
133
docs/concepts/oauth.md
Normal 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; don’t 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)
|
||||
|
||||
Clawdbot’s 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 can’t bind (or you’re 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)
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 you’ve 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 don’t 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
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user