From ff3cf3de3b56df1f04fcdd99db810c1ca26a18cb Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 27 Aug 2026 09:40:27 -0700 Subject: [PATCH] docs(start): correct headless credential handoff to the SQLite auth store (#131024) --- docs/cli/security.md | 2 +- docs/concepts/delegate-architecture.md | 8 ++-- docs/gateway/config-tools.md | 4 +- docs/gateway/configuration-examples.md | 2 +- docs/gateway/doctor.md | 2 +- docs/gateway/secrets-plan-contract.md | 13 +++--- docs/gateway/secrets.md | 2 +- docs/gateway/security/audit-checks.md | 4 +- docs/gateway/security/index.md | 2 +- docs/help/faq-models.md | 40 ++++++++--------- docs/help/faq.md | 15 ++++--- docs/help/testing-live.md | 10 ++--- docs/install/clawdock.md | 2 +- docs/install/digitalocean.md | 2 +- docs/install/docker-vm-runtime.md | 22 +++++----- docs/install/docker.md | 2 +- docs/install/exe-dev.md | 2 +- docs/install/migrating.md | 4 +- docs/install/northflank.mdx | 2 +- docs/install/oracle.md | 2 +- docs/install/podman.md | 2 +- docs/install/railway.mdx | 2 +- docs/install/raspberry-pi.md | 2 +- docs/platforms/easyrunner.md | 4 +- docs/plugins/copilot.md | 2 +- docs/plugins/vault.md | 2 +- docs/providers/ollama.md | 2 +- docs/reference/api-usage-costs.md | 2 +- .../reference/secretref-credential-surface.md | 2 +- docs/start/setup.md | 4 +- docs/start/wizard-cli-reference.md | 44 +++++++++++++++---- 31 files changed, 121 insertions(+), 89 deletions(-) diff --git a/docs/cli/security.md b/docs/cli/security.md index 657d014b682f..9a14918904f8 100644 --- a/docs/cli/security.md +++ b/docs/cli/security.md @@ -124,7 +124,7 @@ Applies safe, deterministic remediations: - flips common `groupPolicy="open"` to `groupPolicy="allowlist"` (including account variants in supported channels) - when WhatsApp group policy flips to `allowlist`, seeds `groupAllowFrom` from the stored `allowFrom` file when that list exists and config does not already define `allowFrom` -- tightens permissions for state/config and common sensitive files (`credentials/*.json`, `auth-profiles.json`, `openclaw-agent.sqlite`, and legacy session artifacts) +- tightens permissions for state/config and common sensitive files (`credentials/*.json`, legacy `auth-profiles.json`, `openclaw-agent.sqlite`, and legacy session artifacts) - also tightens config include files referenced from `openclaw.json` - uses `chmod` on POSIX hosts and `icacls` resets on Windows diff --git a/docs/concepts/delegate-architecture.md b/docs/concepts/delegate-architecture.md index 8186b124c65e..3c1ed6da9d83 100644 --- a/docs/concepts/delegate-architecture.md +++ b/docs/concepts/delegate-architecture.md @@ -238,14 +238,14 @@ Route inbound messages to the delegate agent using [Multi-Agent Routing](/concep ### 4. Add credentials to the delegate agent -Copy or create auth profiles for the delegate's own `agentDir`: +Agents read shared auth profiles without copying them. To give the delegate an +independent provider account, sign in on the Gateway host for that agent: ```bash -# Delegate reads from its own auth store -~/.openclaw/agents/delegate/agent/auth-profiles.json +openclaw models auth login --provider --agent delegate ``` -Never share the main agent's `agentDir` with the delegate. See [Multi-Agent Routing](/concepts/multi-agent) for auth isolation details. +The login writes the delegate's SQLite auth store at `~/.openclaw/agents/delegate/agent/openclaw-agent.sqlite`; its local profiles override the shared read-through base. Never share the main agent's `agentDir` with the delegate. See [Auth credential semantics](/auth-credential-semantics#agent-copy-portability) and [Multi-Agent Routing](/concepts/multi-agent) for auth isolation details. ## Example: organizational assistant diff --git a/docs/gateway/config-tools.md b/docs/gateway/config-tools.md index f3a3456bd6e0..e7300e07e128 100644 --- a/docs/gateway/config-tools.md +++ b/docs/gateway/config-tools.md @@ -369,7 +369,7 @@ Configures inbound media understanding (image/audio/video): - `provider`: API provider id (`openai`, `anthropic`, `google`/`gemini`, `groq`, etc.) - `model`: model id override - - `profile` / `preferredProfile`: `auth-profiles.json` profile selection + - `profile` / `preferredProfile`: stored auth-profile selection **CLI entry** (`type: "cli"`): @@ -383,7 +383,7 @@ Configures inbound media understanding (image/audio/video): - Matching image model `timeoutSeconds` entries also apply when the agent calls the explicit `view_image` tool. For image understanding, this timeout applies to the request itself and is not reduced by earlier preparation work. - Failures fall back to the next entry. - Provider auth follows standard order: `auth-profiles.json` → env vars → `models.providers.*.apiKey`. + Provider auth follows standard order: SQLite auth profiles → env vars → `models.providers.*.apiKey`. diff --git a/docs/gateway/configuration-examples.md b/docs/gateway/configuration-examples.md index 4bb1aff65f95..28145dc796a4 100644 --- a/docs/gateway/configuration-examples.md +++ b/docs/gateway/configuration-examples.md @@ -75,7 +75,7 @@ Save to `~/.openclaw/openclaw.json` and you can DM the bot from that number. }, }, - // Auth profile metadata (secrets live in auth-profiles.json) + // Auth profile metadata (secrets live in SQLite auth stores) auth: { profiles: { "anthropic:default": { provider: "anthropic", mode: "api_key" }, diff --git a/docs/gateway/doctor.md b/docs/gateway/doctor.md index 5eb7b6ffdc6c..2f6a0b478821 100644 --- a/docs/gateway/doctor.md +++ b/docs/gateway/doctor.md @@ -479,7 +479,7 @@ That stages grounded durable candidates into the short-term dreaming store while Doctor also reports auth profiles that are temporarily unusable due to short cooldowns (rate limits/timeouts/auth failures) or longer disables (billing/credit failures). - Legacy Codex OAuth profiles whose tokens live in macOS Keychain (older onboarding before the file-based sidecar layout) are repaired only by doctor. Run `openclaw doctor --fix` once from an interactive terminal to migrate Keychain-backed legacy tokens inline into `auth-profiles.json`; after that, embedded turns (Telegram, cron, sub-agent dispatch) resolve them as canonical OpenAI OAuth profiles. + Legacy Codex OAuth profiles with encrypted sidecar credentials are repaired only by doctor. Run `openclaw doctor --fix` from an interactive terminal on the original host so it can recover the legacy encryption key, including from macOS Keychain when needed, and import supported credentials into the SQLite auth store. If the legacy material cannot be recovered, sign in again with `openclaw models auth login --provider openai` on the Gateway host. diff --git a/docs/gateway/secrets-plan-contract.md b/docs/gateway/secrets-plan-contract.md index 1ca3f9827bd5..e79a48d03742 100644 --- a/docs/gateway/secrets-plan-contract.md +++ b/docs/gateway/secrets-plan-contract.md @@ -1,5 +1,5 @@ --- -summary: "Contract for `secrets apply` plans: target validation, path matching, and `auth-profiles.json` target scope" +summary: "Contract for `secrets apply` plans: target validation, path matching, and SQLite auth-profile target scope" read_when: - Generating or reviewing `openclaw secrets apply` plans - Debugging `Invalid plan target path` errors @@ -105,8 +105,8 @@ Each target is validated with all of the following: - Forbidden segments are rejected: `__proto__`, `prototype`, `constructor`. - The normalized path must match the registered path shape for the target type. - If `providerId` or `accountId` is set, it must match the id encoded in the path. -- `auth-profiles.json` targets require `agentId`. -- When creating a new `auth-profiles.json` mapping, include `authProfileProvider`. +- SQLite auth-profile targets require `agentId`. +- When creating a new auth-profile mapping, include `authProfileProvider`. ## Failure behavior @@ -116,7 +116,7 @@ If a target fails validation, apply exits with an error like: Invalid plan target path for models.providers.apiKey: models.providers.openai.baseUrl ``` -No writes are committed for an invalid plan: target resolution and path validation run before any file is touched. Separately, once a valid plan starts writing, apply snapshots every touched file first and restores those snapshots if a later write in the same run fails, so a partial write never leaves config, auth-profile, or env state out of sync. +No writes are committed for an invalid plan: target resolution and path validation run before any state is changed. For a valid plan, apply captures file snapshots and SQLite auth-store snapshots before writing. If a later write fails, it attempts to restore the files and conditionally roll back the auth-store writes without overwriting concurrent credential changes. ## Exec provider consent behavior @@ -126,8 +126,9 @@ No writes are committed for an invalid plan: target resolution and path validati ## Runtime and audit scope notes -- Ref-only `auth-profiles.json` entries (`keyRef`/`tokenRef`) are included in runtime credential resolution and audit coverage. -- `secrets apply` writes supported `openclaw.json` targets, supported `auth-profiles.json` targets, and three optional scrub passes, each on by default: `scrubEnv` (removes migrated plaintext values from `.env` files in the effective state and active-config directories), `scrubAuthProfilesForProviderTargets` (clears plaintext/unused-ref residue in `auth-profiles.json` for providers a plan just migrated), and `scrubLegacyAuthJson` (drops migrated `api_key` entries from legacy `auth.json` stores). Set any of `options.scrubEnv`, `options.scrubAuthProfilesForProviderTargets`, `options.scrubLegacyAuthJson` to `false` in the plan to skip that pass. +- Ref-only SQLite auth-profile entries (`keyRef`/`tokenRef`) are included in runtime credential resolution and audit coverage. +- `secrets apply` writes supported `openclaw.json` targets and SQLite auth-profile targets. Two optional scrub passes are on by default: `scrubEnv` removes migrated plaintext values from `.env` files in the effective state and active-config directories; `scrubAuthProfilesForProviderTargets` clears plaintext/unused-ref residue in auth stores for providers a plan just migrated. Set either option to `false` in the plan to skip that pass. +- `scrubLegacyAuthJson` is a deprecated plan input and is always disabled. Doctor owns legacy `auth.json` migration; `secrets apply` does not read or rewrite it. ## Operator checks diff --git a/docs/gateway/secrets.md b/docs/gateway/secrets.md index a37a6c4cc79e..3d5d6dfb7325 100644 --- a/docs/gateway/secrets.md +++ b/docs/gateway/secrets.md @@ -1,7 +1,7 @@ --- summary: "Secrets management: SecretRef contract, shared secret store, runtime snapshots, and safe one-way scrubbing" read_when: - - Configuring SecretRefs for provider credentials and `auth-profiles.json` refs + - Configuring SecretRefs for provider credentials and SQLite auth-profile refs - Storing team-wide secrets and environment values in the shared SQLite store - Operating secrets reload, audit, configure, and apply safely in production - Understanding startup fail-fast, inactive-surface filtering, and last-known-good behavior diff --git a/docs/gateway/security/audit-checks.md b/docs/gateway/security/audit-checks.md index 8491d0bf463d..5a7ac57a35cd 100644 --- a/docs/gateway/security/audit-checks.md +++ b/docs/gateway/security/audit-checks.md @@ -34,8 +34,8 @@ exhaustive): | `fs.config_include.perms_writable` | critical | Config include file can be modified by others | include-file perms referenced from `openclaw.json` | yes | | `fs.config_include.perms_group_readable` | warn | Group users can read included secrets/settings | include-file perms referenced from `openclaw.json` | yes | | `fs.config_include.perms_world_readable` | critical | Included secrets/settings are world-readable | include-file perms referenced from `openclaw.json` | yes | -| `fs.auth_profiles.perms_writable` | critical | Others can inject or replace stored model credentials | `agents//agent/auth-profiles.json` perms | yes | -| `fs.auth_profiles.perms_readable` | warn | Others can read API keys and OAuth tokens | `agents//agent/auth-profiles.json` perms | yes | +| `fs.auth_profiles.perms_writable` | critical | Others can inject or replace stored model credentials | Agent-local SQLite auth database/sidecar perms and legacy `auth-profiles.json` perms | yes | +| `fs.auth_profiles.perms_readable` | warn | Others can read API keys and OAuth tokens | Agent-local SQLite auth database/sidecar perms and legacy `auth-profiles.json` perms | yes | | `fs.credentials_dir.perms_writable` | critical | Others can modify channel pairing/credential state | filesystem perms on `~/.openclaw/credentials` | yes | | `fs.credentials_dir.perms_readable` | warn | Others can read channel credential state | filesystem perms on `~/.openclaw/credentials` | yes | | `fs.sessions_store.perms_readable` | warn | Others can read session transcripts/metadata | session store perms | yes | diff --git a/docs/gateway/security/index.md b/docs/gateway/security/index.md index 11bc27bc9697..6f1aa4d3308d 100644 --- a/docs/gateway/security/index.md +++ b/docs/gateway/security/index.md @@ -862,7 +862,7 @@ For phone-number-based channels, consider running the assistant on a separate nu 1. Rotate Gateway auth (`gateway.auth.token` / `OPENCLAW_GATEWAY_PASSWORD`) and restart. 2. Rotate remote client secrets (`gateway.remote.token` / `.password`) on any machine that can call the Gateway. -3. Rotate provider/API credentials (WhatsApp creds, Slack/Discord tokens, model/API keys in `auth-profiles.json`, and encrypted secrets payload values when used). +3. Rotate provider/API credentials (WhatsApp creds, Slack/Discord tokens, model/API keys in SQLite auth stores, and encrypted secrets payload values when used). ### Audit diff --git a/docs/help/faq-models.md b/docs/help/faq-models.md index 012541a2afdb..bc261426d642 100644 --- a/docs/help/faq-models.md +++ b/docs/help/faq-models.md @@ -323,16 +323,16 @@ troubleshooting, see the main [FAQ](/help/faq). **No API key found for provider after adding a new agent** - A new agent has an empty auth store — auth is per-agent, stored at: + A new agent can read shared auth profiles without copying them. Its + own profiles live in `~/.openclaw/agents//agent/openclaw-agent.sqlite` + and override the shared read-through base. See + [Auth credential semantics](/auth-credential-semantics#agent-copy-portability). - ```text - ~/.openclaw/agents//agent/auth-profiles.json - ``` - - Fix: run `openclaw agents add ` and configure auth in the wizard, or - copy only portable static `api_key`/`token` profiles from the main - agent's store. For OAuth, sign in from the new agent when it needs its - own account. See [Multi-Agent Routing](/concepts/multi-agent) for the + Fix: run `openclaw models auth login --provider --agent ` + on the Gateway host when the agent needs its own credentials. You can also + configure auth when creating an agent with `openclaw agents add `. + For OAuth, sign in separately when the agent needs its own account. + See [Multi-Agent Routing](/concepts/multi-agent) for the full `agentDir` reuse and credential-sharing rules — never reuse `agentDir` across agents. @@ -391,14 +391,14 @@ troubleshooting, see the main [FAQ](/help/faq). **Fix checklist:** - - Confirm where profiles live — current: - `~/.openclaw/agents//agent/auth-profiles.json`; legacy: - `~/.openclaw/agent/*` (migrated by `openclaw doctor`). + - Confirm where profiles live: shared and agent-local SQLite auth stores. + Run `openclaw doctor --fix` if an older install still has + `auth-profiles.json`; it is a migration source, not the runtime store. - Confirm the Gateway loads your env var. `ANTHROPIC_API_KEY` set only in your shell won't reach a Gateway run via systemd/launchd — put it in `~/.openclaw/.env` or enable `env.shellEnv`. - - Confirm you're editing the right agent — multi-agent setups have - multiple `auth-profiles.json` files. + - Confirm you're configuring the right agent — use `--agent ` + with `openclaw models auth login` to select its local store. - Run `openclaw models status` to see configured models and provider auth state. @@ -445,12 +445,12 @@ Related: [/concepts/oauth](/concepts/oauth) (OAuth flows, token storage, multi-a - A named credential record (OAuth or API key) tied to a provider, stored - at: - - ```text - ~/.openclaw/agents//agent/auth-profiles.json - ``` + A named credential record (API key, token, or OAuth) tied to a provider, + stored in SQLite. Agent-local profiles in + `~/.openclaw/agents//agent/openclaw-agent.sqlite` override the + shared read-through base in `~/.openclaw/state/openclaw.sqlite`. + Older installs keep the shared store in the main agent's database until + `openclaw doctor --fix` relocates it. Inspect saved profiles without dumping secrets: `openclaw models auth list` (optionally `--provider ` or `--json`). See diff --git a/docs/help/faq.md b/docs/help/faq.md index 107cf996a269..59d76ef5c210 100644 --- a/docs/help/faq.md +++ b/docs/help/faq.md @@ -462,17 +462,22 @@ First-run Q&A - install, onboard, auth routes, subscriptions, initial failures - | Path | Purpose | | ------------------------------------------------------------------ | ------------------------------------------------------------------ | | `$OPENCLAW_STATE_DIR/openclaw.json` | Main config (JSON5) | - | `$OPENCLAW_STATE_DIR/credentials/oauth.json` | Legacy OAuth import (copied into auth profiles on first use) | - | `$OPENCLAW_STATE_DIR/agents//agent/auth-profiles.json` | Auth profiles (OAuth, API keys, optional `keyRef`/`tokenRef`) | + | `$OPENCLAW_STATE_DIR/credentials/oauth.json` | Legacy OAuth migration source for `openclaw doctor --fix` | + | `$OPENCLAW_STATE_DIR/state/openclaw.sqlite` | Shared SQLite state, including shared auth profiles | | `$OPENCLAW_STATE_DIR/secrets.json` | Optional file-backed secret payload for `file` SecretRef providers | - | `$OPENCLAW_STATE_DIR/agents//agent/auth.json` | Legacy compatibility file (static `api_key` entries scrubbed) | + | `$OPENCLAW_STATE_DIR/agents//agent/auth.json` | Legacy auth migration source for `openclaw doctor --fix` | | `$OPENCLAW_STATE_DIR/credentials/` | Provider state (for example `whatsapp//creds.json`) | | `$OPENCLAW_STATE_DIR/agents/` | Per-agent state (agentDir + legacy/archive session artifacts) | - | `$OPENCLAW_STATE_DIR/agents//agent/openclaw-agent.sqlite` | Per-agent SQLite state, including session rows and transcripts | + | `$OPENCLAW_STATE_DIR/agents//agent/openclaw-agent.sqlite` | Per-agent SQLite state, including local auth profiles, sessions, and transcripts | | `$OPENCLAW_STATE_DIR/agents//sessions/` | Legacy session migration sources and archive/support artifacts | Legacy single-agent path `~/.openclaw/agent/*` is migrated by `openclaw doctor`. + Legacy `auth-profiles.json` files are imported by `openclaw doctor --fix`; + new logins write SQLite. Agent-local profiles override the shared read-through + base. Older installs keep that shared store in the main agent's database until + doctor relocates it; see [Auth credential semantics](/auth-credential-semantics#agent-copy-portability). + Your **workspace** (AGENTS.md, memory files, skills, etc.) is separate, configured via `agents.defaults.workspace` (default: `~/.openclaw/workspace`). @@ -1571,7 +1576,7 @@ Model Q&A - defaults, selection, aliases, switching, failover, auth profiles - l - Credentials and model selection are separate. Setting `ANTHROPIC_API_KEY` (or storing an Anthropic API key in auth profiles) enables authentication, but the actual default model is whatever you configure in `agents.defaults.model.primary` (for example `anthropic/claude-sonnet-4-6` or `anthropic/claude-opus-4-6`). `No credentials found for profile "anthropic:default"` means the Gateway could not find Anthropic credentials in the expected `auth-profiles.json` for the running agent. + Credentials and model selection are separate. Setting `ANTHROPIC_API_KEY` (or storing an Anthropic API key in auth profiles) enables authentication, but the actual default model is whatever you configure in `agents.defaults.model.primary` (for example `anthropic/claude-sonnet-4-6` or `anthropic/claude-opus-4-6`). `No credentials found for profile "anthropic:default"` means the Gateway could not find Anthropic credentials in the SQLite auth stores available to the running agent. diff --git a/docs/help/testing-live.md b/docs/help/testing-live.md index bf2c56885786..023d7ebdca0d 100644 --- a/docs/help/testing-live.md +++ b/docs/help/testing-live.md @@ -667,10 +667,10 @@ Live tests discover credentials the same way the CLI does. Practical implication - If the CLI works, live tests should find the same keys. - If a live test says "no creds", debug the same way you'd debug `openclaw models list` / model selection. -- Per-agent auth profiles: `~/.openclaw/agents//agent/auth-profiles.json` (this is what "profile keys" means in the live tests) +- Per-agent auth profiles: SQLite credential rows in `~/.openclaw/agents//agent/openclaw-agent.sqlite` (this is what "profile keys" means in the live tests) - Config: `~/.openclaw/openclaw.json` (or `OPENCLAW_CONFIG_PATH`) - Legacy OAuth dir: `~/.openclaw/credentials/` (copied into the staged live home when present, but not the main profile-key store) -- Local live runs copy the active config (with `agents.*.workspace` / `agentDir` overrides stripped) and each agent's `auth-profiles.json` - not the rest of that agent's directory, so `workspace/` and `sandboxes/` data never reaches the staged home - plus the legacy `credentials/` dir and supported external CLI auth files/dirs (`.claude.json`, `.claude/.credentials.json`, `.claude/settings*.json`, `.claude/backups`, `.codex/auth.json`, `.codex/config.toml`, `.gemini`, `.minimax`) into a temp test home. +- Local live runs copy the active config (with `agents.*.workspace` / `agentDir` overrides stripped) and stage each agent's canonical SQLite auth credential/state rows through the auth-store reader/writer APIs, not by copying its database or the rest of its directory. Agent sessions, `workspace/`, and `sandboxes/` data are not staged. The runner also copies the legacy `credentials/` dir and supported external CLI auth files/dirs (`.claude.json`, `.claude/.credentials.json`, `.claude/settings*.json`, `.claude/backups`, `.codex/auth.json`, `.codex/config.toml`, `.gemini`, `.minimax`) into a temp test home. If you want to rely on env keys, export them before local tests or use the Docker runners below with an explicit `OPENCLAW_PROFILE_FILE`. @@ -703,7 +703,7 @@ Docker runners below with an explicit `OPENCLAW_PROFILE_FILE`. - Scope: - Enumerates every registered image-generation provider plugin - Uses already-exported provider env vars before probing - - Uses live/env API keys ahead of stored auth profiles by default, so stale test keys in `auth-profiles.json` do not mask real shell credentials + - Uses live/env API keys ahead of stored auth profiles by default, so stale test keys in SQLite auth stores do not mask real shell credentials - Skips providers with no usable auth/profile/model - Runs each configured provider through the shared image-generation runtime: - `:generate` @@ -751,7 +751,7 @@ request. Plugin dependencies are expected to be present before runtime load. - Exercises the shared bundled music-generation provider path - Currently covers `fal`, `google`, `minimax`, and `openrouter` - Uses already-exported provider env vars before probing - - Uses live/env API keys ahead of stored auth profiles by default, so stale test keys in `auth-profiles.json` do not mask real shell credentials + - Uses live/env API keys ahead of stored auth profiles by default, so stale test keys in SQLite auth stores do not mask real shell credentials - Skips providers with no usable auth/profile/model - Runs both declared runtime modes when available: - `generate` with prompt-only input @@ -773,7 +773,7 @@ request. Plugin dependencies are expected to be present before runtime load. - Defaults to the release-safe smoke path: one text-to-video request per provider, one-second lobster prompt, and a per-provider operation cap from `OPENCLAW_LIVE_VIDEO_GENERATION_TIMEOUT_MS` (`180000` by default) - Skips FAL by default because provider-side queue latency can dominate release time; pass `OPENCLAW_LIVE_VIDEO_GENERATION_PROVIDERS="fal"` (or clear the skip list) to run it explicitly - Uses already-exported provider env vars before probing - - Uses live/env API keys ahead of stored auth profiles by default, so stale test keys in `auth-profiles.json` do not mask real shell credentials + - Uses live/env API keys ahead of stored auth profiles by default, so stale test keys in SQLite auth stores do not mask real shell credentials - Skips providers with no usable auth/profile/model - Runs only `generate` by default - Set `OPENCLAW_LIVE_VIDEO_GENERATION_FULL_MODES=1` to also run declared transform modes when available: diff --git a/docs/install/clawdock.md b/docs/install/clawdock.md index 9e3c3da08192..32d9561d1514 100644 --- a/docs/install/clawdock.md +++ b/docs/install/clawdock.md @@ -92,7 +92,7 @@ clawdock-approve ClawDock reads two separate `.env` files, matching the split described in [Docker](/install/docker): - The project `.env` next to `docker-compose.yml`: Docker-specific values like image name, ports, and `OPENCLAW_GATEWAY_TOKEN`. `clawdock-token` reads the token from here. -- `~/.openclaw/.env` (mounted into the container): env-backed secrets OpenClaw itself manages, alongside `openclaw.json` and `agents//agent/auth-profiles.json`. +- `~/.openclaw/.env` (mounted into the container): env-backed secrets OpenClaw itself manages, alongside `openclaw.json` and the shared and per-agent SQLite auth stores. `clawdock-fix-token` copies the token from the project `.env` into the container's `gateway.remote.token` and `gateway.auth.token` config values and restarts the gateway. diff --git a/docs/install/digitalocean.md b/docs/install/digitalocean.md index b8db267a176e..b457e8632f48 100644 --- a/docs/install/digitalocean.md +++ b/docs/install/digitalocean.md @@ -123,7 +123,7 @@ DigitalOcean is a straightforward paid VPS path. For cheaper or free options: OpenClaw state lives under: -- `~/.openclaw/` -- `openclaw.json`, channel/provider credentials, per-agent `auth-profiles.json`, and session data. +- `~/.openclaw/` -- `openclaw.json`, channel/provider credentials, shared and per-agent SQLite auth stores, and session data. - `~/.openclaw/workspace/` -- the agent workspace (SOUL.md, memory, artifacts). These survive Droplet reboots. To take a portable snapshot: diff --git a/docs/install/docker-vm-runtime.md b/docs/install/docker-vm-runtime.md index e1512fa8d361..ce8dc18c4689 100644 --- a/docs/install/docker-vm-runtime.md +++ b/docs/install/docker-vm-runtime.md @@ -154,17 +154,17 @@ docker compose run --rm openclaw-cli devices approve OpenClaw runs in Docker, but the container filesystem is not the source of truth. Long-lived state must survive restarts, rebuilds, and reboots. -| Component | Container location | Persistence mechanism | Notes | -| -------------------- | ----------------------------------- | --------------------------- | -------------------------------------------------------------------------- | -| Gateway state/config | `/home/node/.openclaw/` | `OPENCLAW_CONFIG_DIR` mount | Includes `openclaw.json`, shared state, and installed plugin package roots | -| Agent workspace | `/home/node/.openclaw/workspace/` | Workspace mount | Code and agent artifacts | -| Channel credentials | `/home/node/.openclaw/credentials/` | Config mount | Channel credential material | -| Model auth profiles | `/home/node/.openclaw/agents/` | Config mount | `agents//agent/auth-profiles.json` | -| Auth-profile key | `/home/node/.config/openclaw/` | Secret-directory mount | Encryption key material; keep separate from the config mount | -| Skill state | `/home/node/.openclaw/skills/` | Config mount | Skill-level state | -| External binaries | `/usr/local/bin/` | Docker image | Must be baked at build time | -| Node and OS packages | Container filesystem | Docker image | Rebuilt with the image; do not install at runtime | -| Docker container | Ephemeral | Restartable | Safe to replace after mounted state is verified | +| Component | Container location | Persistence mechanism | Notes | +| -------------------- | ----------------------------------- | --------------------------- | ------------------------------------------------------------------------------------------ | +| Gateway state/config | `/home/node/.openclaw/` | `OPENCLAW_CONFIG_DIR` mount | Includes `openclaw.json`, shared state, and installed plugin package roots | +| Agent workspace | `/home/node/.openclaw/workspace/` | Workspace mount | Code and agent artifacts | +| Channel credentials | `/home/node/.openclaw/credentials/` | Config mount | Channel credential material | +| Model auth profiles | `/home/node/.openclaw/` | Config mount | Shared `state/openclaw.sqlite`; agent-local `agents//agent/openclaw-agent.sqlite` | +| Auth-profile key | `/home/node/.config/openclaw/` | Secret-directory mount | Encryption key material; keep separate from the config mount | +| Skill state | `/home/node/.openclaw/skills/` | Config mount | Skill-level state | +| External binaries | `/usr/local/bin/` | Docker image | Must be baked at build time | +| Node and OS packages | Container filesystem | Docker image | Rebuilt with the image; do not install at runtime | +| Docker container | Ephemeral | Restartable | Safe to replace after mounted state is verified | ## Update OpenClaw diff --git a/docs/install/docker.md b/docs/install/docker.md index 366d309ba7d7..c2a1ed14c85e 100644 --- a/docs/install/docker.md +++ b/docs/install/docker.md @@ -440,7 +440,7 @@ Docker Compose bind-mounts `OPENCLAW_CONFIG_DIR` to `/home/node/.openclaw`, `OPE That mounted config directory holds: - `openclaw.json` for behavior config -- `agents//agent/auth-profiles.json` for stored provider OAuth/API-key auth +- `state/openclaw.sqlite` for shared provider auth and `agents//agent/openclaw-agent.sqlite` for agent-local OAuth/API-key profiles - `.env` for env-backed runtime secrets such as `OPENCLAW_GATEWAY_TOKEN` The auth-profile secret directory stores the local encryption key for OAuth-backed auth profile token material. Keep it with your Docker host state, but separate from `OPENCLAW_CONFIG_DIR`. diff --git a/docs/install/exe-dev.md b/docs/install/exe-dev.md index c0bbd5d4913d..2fd5bb204c05 100644 --- a/docs/install/exe-dev.md +++ b/docs/install/exe-dev.md @@ -48,7 +48,7 @@ Set up OpenClaw (https://docs.openclaw.ai/install) on this VM. Use the non-inter ``` - Keep this VM **stateful**. OpenClaw stores `openclaw.json`, per-agent `auth-profiles.json`, sessions, and channel/provider state under `~/.openclaw/`, plus the workspace under `~/.openclaw/workspace/`. + Keep this VM **stateful**. OpenClaw stores `openclaw.json`, shared and per-agent SQLite auth stores, sessions, and channel/provider state under `~/.openclaw/`, plus the workspace under `~/.openclaw/workspace/`. diff --git a/docs/install/migrating.md b/docs/install/migrating.md index 20682d7c89f1..cbbb445dbe20 100644 --- a/docs/install/migrating.md +++ b/docs/install/migrating.md @@ -29,7 +29,7 @@ The CLI entry point is [`openclaw migrate`](/cli/migrate). Onboarding can also o Copy the **state directory** (`~/.openclaw/` by default) and your **workspace** to preserve: - **Config** — `openclaw.json` and all gateway settings. -- **Auth** — per-agent `auth-profiles.json` (API keys plus OAuth), plus any channel or provider state under `credentials/`. +- **Auth** — shared and per-agent SQLite auth stores (API keys plus OAuth), plus any channel or provider state under `credentials/`. - **Sessions** — conversation history and agent state. - **Channel state** — WhatsApp login, Telegram session, and similar. - **Workspace files** — `MEMORY.md`, `USER.md`, skills, and prompts. @@ -112,7 +112,7 @@ awk -F= '/^(TELEGRAM_BOT_TOKEN|DISCORD_BOT_TOKEN)=/ { print $1 "=present" }' ~/. - The config file alone is not enough. Model auth profiles live under `agents//agent/auth-profiles.json`, and channel and provider state lives under `credentials/`. Always migrate the **entire** state directory. + The config file alone is not enough. Shared model auth lives in `state/openclaw.sqlite`, agent-local profiles live in `agents//agent/openclaw-agent.sqlite`, and channel and provider state lives under `credentials/`. Always migrate the **entire** state directory using the backup and restore flow above. diff --git a/docs/install/northflank.mdx b/docs/install/northflank.mdx index 59089327ca6f..69d1af9e3a70 100644 --- a/docs/install/northflank.mdx +++ b/docs/install/northflank.mdx @@ -31,7 +31,7 @@ openclaw doctor --json ## What you get - Hosted OpenClaw Gateway + Control UI -- Persistent storage via a Northflank Volume (`/data`) so `openclaw.json`, per-agent `auth-profiles.json`, channel/provider state, sessions, and workspace survive redeploys +- Persistent storage via a Northflank Volume (`/data`) so `openclaw.json`, shared and per-agent SQLite auth stores, channel/provider state, sessions, and workspace survive redeploys ## Connect a channel diff --git a/docs/install/oracle.md b/docs/install/oracle.md index afd15245ff14..264f1ec7040a 100644 --- a/docs/install/oracle.md +++ b/docs/install/oracle.md @@ -177,7 +177,7 @@ Verify the architecture with `uname -m` (should print `aarch64`). For binaries w OpenClaw state lives under: -- `~/.openclaw/` -- `openclaw.json`, per-agent `auth-profiles.json`, channel/provider state, and session data. +- `~/.openclaw/` -- `openclaw.json`, shared and per-agent SQLite auth stores, channel/provider state, and session data. - `~/.openclaw/workspace/` -- the agent workspace (SOUL.md, memory, artifacts). These survive reboots. To take a portable snapshot: diff --git a/docs/install/podman.md b/docs/install/podman.md index c67a85e8019f..684823503b92 100644 --- a/docs/install/podman.md +++ b/docs/install/podman.md @@ -145,7 +145,7 @@ The generated Quadlet service keeps a fixed, hardened default shape: `127.0.0.1` - **Token file:** `~/.openclaw/.env` - **Launch helper:** `./scripts/run-openclaw-podman.sh` -The launch script and Quadlet bind-mount host state into the container: `OPENCLAW_CONFIG_DIR` -> `/home/node/.openclaw`, `OPENCLAW_WORKSPACE_DIR` -> `/home/node/.openclaw/workspace`. By default those are host directories, not anonymous container state, so `openclaw.json`, per-agent `auth-profiles.json`, channel/provider state, sessions, and workspace survive container replacement. Setup also seeds `gateway.controlUi.allowedOrigins` for `127.0.0.1` and `localhost` on the published gateway port so the local dashboard works with the container's non-loopback bind. +The launch script and Quadlet bind-mount host state into the container: `OPENCLAW_CONFIG_DIR` -> `/home/node/.openclaw`, `OPENCLAW_WORKSPACE_DIR` -> `/home/node/.openclaw/workspace`. By default those are host directories, not anonymous container state, so `openclaw.json`, shared and per-agent SQLite auth stores, channel/provider state, sessions, and workspace survive container replacement. Setup also seeds `gateway.controlUi.allowedOrigins` for `127.0.0.1` and `localhost` on the published gateway port so the local dashboard works with the container's non-loopback bind. Useful env vars for the manual launcher (persist these in `~/.openclaw/.env`; the launcher reads that file before finalizing container/image defaults): diff --git a/docs/install/railway.mdx b/docs/install/railway.mdx index da7c8ef7dda7..ca9d01fd9cd9 100644 --- a/docs/install/railway.mdx +++ b/docs/install/railway.mdx @@ -54,7 +54,7 @@ openclaw doctor --json ## What you get - Hosted OpenClaw Gateway + Control UI -- Persistent storage via the Railway Volume (`/data`), so `openclaw.json`, per-agent `auth-profiles.json`, channel/provider state, sessions, and workspace survive redeploys +- Persistent storage via the Railway Volume (`/data`), so `openclaw.json`, shared and per-agent SQLite auth stores, channel/provider state, sessions, and workspace survive redeploys ## Connect a channel diff --git a/docs/install/raspberry-pi.md b/docs/install/raspberry-pi.md index d4072e02d9de..cc90969bf5d7 100644 --- a/docs/install/raspberry-pi.md +++ b/docs/install/raspberry-pi.md @@ -194,7 +194,7 @@ Most OpenClaw features work on ARM64 without changes (Node.js, Telegram, WhatsAp OpenClaw state lives under: -- `~/.openclaw/` -- `openclaw.json`, per-agent `auth-profiles.json`, channel/provider state, sessions. +- `~/.openclaw/` -- `openclaw.json`, shared and per-agent SQLite auth stores, channel/provider state, sessions. - `~/.openclaw/workspace/` -- agent workspace (SOUL.md, memory, artifacts). These survive reboots and benefit from SSD over SD card for both performance and longevity. Take a portable snapshot with: diff --git a/docs/platforms/easyrunner.md b/docs/platforms/easyrunner.md index 7a56200b32cf..9b27d9c2e784 100644 --- a/docs/platforms/easyrunner.md +++ b/docs/platforms/easyrunner.md @@ -97,8 +97,8 @@ SecretRef, plugin, or channel auth failures. - Pull or build the new OpenClaw image, then redeploy the EasyRunner app. - Back up the `openclaw-config` volume before updates. It holds - `openclaw.json`, `agents//agent/auth-profiles.json`, and installed - plugin package state. + `openclaw.json`, shared auth in `state/openclaw.sqlite`, agent-local profiles + in `agents//agent/openclaw-agent.sqlite`, and installed plugin package state. - Back up `openclaw-workspace` if agents write durable project data there. - Run `openclaw doctor` after major updates to catch config migrations and service warnings. diff --git a/docs/plugins/copilot.md b/docs/plugins/copilot.md index 8745755395be..718b9572f91c 100755 --- a/docs/plugins/copilot.md +++ b/docs/plugins/copilot.md @@ -182,7 +182,7 @@ Precedence, applied per agent during `runCopilotAttempt`: Each agent gets its own `copilotHome` so Copilot CLI tokens, sessions, and config never leak between agents on the same machine. Default: `/copilot` (keeps SDK state out of the same directory as -OpenClaw's `models.json` / `auth-profiles.json`), or +OpenClaw's `models.json` / `openclaw-agent.sqlite`), or `~/.openclaw/agents//copilot` when no agent directory is supplied. Override with `copilotHome: ` on the attempt input for a custom location (for example, a shared mount for migration). diff --git a/docs/plugins/vault.md b/docs/plugins/vault.md index 91de504fcc98..40a74ccddd56 100644 --- a/docs/plugins/vault.md +++ b/docs/plugins/vault.md @@ -237,7 +237,7 @@ openclaw vault setup \ ``` Bare target paths apply to `openclaw.json`. Use -`auth-profiles::` for existing `auth-profiles.json` targets. +`auth-profiles::` for existing SQLite auth-profile targets. The target path must be a registered OpenClaw SecretRef target. The setup command does not create arbitrary named secrets in OpenClaw; Vault remains the secret store, and OpenClaw stores SecretRefs only on supported config fields. diff --git a/docs/providers/ollama.md b/docs/providers/ollama.md index 2c259e7fb2ed..9b50ec86eb1c 100644 --- a/docs/providers/ollama.md +++ b/docs/providers/ollama.md @@ -40,7 +40,7 @@ OpenAI-SDK-style examples, but new config should use `baseUrl`. A custom provider with `api: "ollama"` follows the same rules. For example, an `ollama-remote` provider pointed at a private LAN host can use `apiKey: "ollama-local"`; sub-agents resolve that marker through the Ollama provider hook instead of treating it as a missing credential. `memory.search.provider` can also point at a custom provider id so embeddings use that Ollama endpoint. - `auth-profiles.json` stores the credential for a provider id; put endpoint settings (`baseUrl`, `api`, models, headers, timeouts) in `models.providers.`. Older flat files such as `{ "ollama-windows": { "apiKey": "ollama-local" } }` are not a runtime format; `openclaw doctor --fix` rewrites them into a canonical `ollama-windows:default` API-key profile with a backup. A `baseUrl` value in that legacy file is noise and should move to provider config. + SQLite auth stores hold the credential for a provider id; put endpoint settings (`baseUrl`, `api`, models, headers, timeouts) in `models.providers.`. Older flat `auth-profiles.json` files such as `{ "ollama-windows": { "apiKey": "ollama-local" } }` are not a runtime format; `openclaw doctor --fix` imports them into SQLite as a canonical `ollama-windows:default` API-key profile with a backup. A `baseUrl` value in that legacy file is noise and should move to provider config. Bearer auth for Ollama memory embeddings is scoped to the host it was declared for: diff --git a/docs/reference/api-usage-costs.md b/docs/reference/api-usage-costs.md index aa621e037333..df6db7028b87 100644 --- a/docs/reference/api-usage-costs.md +++ b/docs/reference/api-usage-costs.md @@ -46,7 +46,7 @@ Anthropic has confirmed that Claude CLI reuse (including `claude -p`) is a sanct ## How keys are discovered -- **Auth profiles**: per-agent, stored in `auth-profiles.json`. +- **Auth profiles**: SQLite stores, with agent-local profiles overriding the shared read-through base. See [Auth credential semantics](/auth-credential-semantics#agent-copy-portability). - **Environment variables**: for example `OPENAI_API_KEY`, `BRAVE_API_KEY`, `FIRECRAWL_API_KEY`. - **Config**: `models.providers.*.apiKey`, `plugins.entries.*.config.webSearch.apiKey`, `plugins.entries.firecrawl.config.webFetch.apiKey`, `memory.search.*`, `talk.providers.*.apiKey`. - **Skills**: `skills.entries..apiKey`, which may export the key to the skill process env. diff --git a/docs/reference/secretref-credential-surface.md b/docs/reference/secretref-credential-surface.md index ed41dc8b35a3..73dde098c1b6 100644 --- a/docs/reference/secretref-credential-surface.md +++ b/docs/reference/secretref-credential-surface.md @@ -128,7 +128,7 @@ The lists below are generated from the source target registry and checked agains - `channels.googlechat.serviceAccount` - `channels.googlechat.accounts.*.serviceAccount` -### `auth-profiles.json` targets (`secrets configure` + `secrets apply` + `secrets audit`) +### SQLite auth-profile targets (`secrets configure` + `secrets apply` + `secrets audit`) - `profiles.*.keyRef` (`type: "api_key"`; unsupported when `auth.profiles..mode = "oauth"`) - `profiles.*.tokenRef` (`type: "token"`; unsupported when `auth.profiles..mode = "oauth"`) diff --git a/docs/start/setup.md b/docs/start/setup.md index 2b87936a7c5e..492eb5bebd42 100644 --- a/docs/start/setup.md +++ b/docs/start/setup.md @@ -136,7 +136,7 @@ openclaw health - **Wrong port:** Gateway WS defaults to `ws://127.0.0.1:18789`; keep app + CLI on the same port. - **Where state lives:** - Channel/provider state: `~/.openclaw/credentials/` - - Model auth profiles: `~/.openclaw/agents//agent/auth-profiles.json` + - Model auth profiles: SQLite auth stores (shared: `~/.openclaw/state/openclaw.sqlite`; agent-local: `~/.openclaw/agents//agent/openclaw-agent.sqlite`) - Sessions and transcripts: `~/.openclaw/agents//agent/openclaw-agent.sqlite` - Legacy/archive session artifacts: `~/.openclaw/agents//sessions/` - Logs: `/tmp/openclaw/` @@ -152,7 +152,7 @@ Use this when debugging auth or deciding what to back up: - **Pairing allowlists**: - `~/.openclaw/credentials/-allowFrom.json` (default account) - `~/.openclaw/credentials/--allowFrom.json` (non-default accounts) -- **Model auth profiles**: `~/.openclaw/agents//agent/auth-profiles.json` +- **Model auth profiles**: shared and agent-local SQLite auth stores; see [Auth credential semantics](/auth-credential-semantics#agent-copy-portability) for inheritance and legacy shared-store relocation - **File-backed secrets payload (optional)**: `~/.openclaw/secrets.json` - **Legacy OAuth import**: `~/.openclaw/credentials/oauth.json` More detail: [Security](/gateway/security#credential-storage-map). diff --git a/docs/start/wizard-cli-reference.md b/docs/start/wizard-cli-reference.md index 11ce19aabfcf..c35f23c13c7f 100644 --- a/docs/start/wizard-cli-reference.md +++ b/docs/start/wizard-cli-reference.md @@ -340,8 +340,11 @@ Model behavior: Credential and profile paths: -- Auth profiles (API keys + OAuth): `~/.openclaw/agents//agent/auth-profiles.json` -- Legacy OAuth import: `~/.openclaw/credentials/oauth.json` +- Agent-local auth profiles (API keys, tokens, and OAuth): `~/.openclaw/agents//agent/openclaw-agent.sqlite` (`auth_profile_store`). +- Shared auth profiles: `~/.openclaw/state/openclaw.sqlite`; agent-local profiles override this read-through base. Older installs keep the shared store in the main agent's database until `openclaw doctor --fix` relocates it. +- Legacy import only: `auth-profiles.json`, per-agent `auth.json`, and `~/.openclaw/credentials/oauth.json`. Run `openclaw doctor --fix` to import them into SQLite; new logins do not write these files. + +Paths respect `$OPENCLAW_STATE_DIR`. See [Auth credential semantics](/auth-credential-semantics#agent-copy-portability) for shared-store and agent-local behavior. Credential storage mode: @@ -369,13 +372,36 @@ Credential storage mode: `--gateway-token` and `--gateway-token-ref-env` are mutually exclusive. - Existing plaintext setups continue to work unchanged. - -Headless and server tip: complete OAuth on a machine with a browser, then copy -that agent's `auth-profiles.json` (for example -`~/.openclaw/agents//agent/auth-profiles.json`, or the matching -`$OPENCLAW_STATE_DIR/...` path) to the gateway host. `credentials/oauth.json` -is only a legacy import source. - +## Headless and server setup + +Run auth setup **on the Gateway host**, using the same OS user and state directory +as the Gateway. Over SSH, use an interactive terminal: + +```bash +openclaw configure --section model +``` + +Choose your provider's supported auth method. For a browser OAuth flow, open the +displayed URL in your local browser and paste the redirect URL or authorization +code back into the terminal on the Gateway host when prompted. If the provider +offers device-code login, complete the displayed URL/code in your local browser +while the Gateway host's login process waits. The completed login persists the +credential on that host in SQLite; no credential file handoff is needed. + +For a specific agent, run `openclaw models auth login --provider --agent ` +on the Gateway host. See [Models CLI](/cli/models#auth-profiles) and +[OAuth](/concepts/oauth). + +For unattended setup, use a provider API key with +[non-interactive onboarding](/cli/onboard#non-interactive-setup). If you use +`--secret-input-mode ref`, make the referenced environment variable available to +the Gateway service as well as the onboarding process. See +[Authentication](/gateway/authentication). + +Verify the result on the Gateway host with `openclaw models status` (add +`--agent ` for a specific agent). Remote-client onboarding only configures +the local client connection; it does not set up provider credentials on the server. +Do not copy `auth-profiles.json` or replace a SQLite database to transfer a login. ## Outputs and internals