Model Provider Authentication: OAuth, API Keys, and Setup Tokens

Learn how to authenticate with model providers using API keys, OAuth, Claude CLI reuse, or the Anthropic setup-token. Essential for gateway operators and developers configuring model access.

Read this when

  • Debugging model auth or OAuth expiry
  • Documenting authentication or credential storage

Note

Model provider authentication, covering API keys, OAuth, Claude CLI reuse, and the Anthropic setup-token, is the subject of this page. For authentication tied to gateway connections, including tokens, passwords, and trusted proxies, refer to Configuration and Trusted Proxy Auth.

Both OAuth and API keys are supported by OpenClaw for model providers. When the gateway runs continuously, an API key tends to be the most reliable choice, though subscription or OAuth flows remain viable if they align with how your provider account is set up.

  1. Generate an API key from your provider's console.
  2. Place it on the gateway host, which is the machine where openclaw gateway runs:
export <PROVIDER>_API_KEY="..."
openclaw models status
  1. When the gateway is managed by systemd or launchd, store the key in ~/.openclaw/.env so the daemon has access to it:
cat >> ~/.openclaw/.env <<'EOF'
<PROVIDER>_API_KEY=...
EOF
  1. Restart the gateway process or the daemon, then verify again:
openclaw models status
openclaw doctor

If managing environment variables manually is not something you want to do, openclaw onboard can hold API keys for daemon use as well. The complete env-loading precedence, covering env.shellEnv, ~/.openclaw/.env, and systemd/launchd, is documented under Environment variables.

Anthropic: Claude CLI reuse

The Anthropic setup-token authentication path is still supported. Reusing a Claude CLI login, in the claude -p style, is also permitted for this integration, and when such a login exists on the host it becomes the preferred route for local or desktop usage. For gateways meant to run long-term, an Anthropic API key remains the most predictable option since it gives explicit billing control on the server side.

Preparing the host for Claude CLI reuse:

# Run on the gateway host
claude auth login
claude auth status --text
openclaw models auth login --provider anthropic --method cli --set-default

This involves two actions: logging Claude Code into Anthropic on the host, then configuring OpenClaw so Anthropic model selection goes through the local claude-cli backend while the matching OpenClaw auth profile is stored.

At runtime, a reused Claude CLI login is treated by OpenClaw as Claude's own credential. The current claude login on the host is checked against the account tied to the selected profile, after which the claude subprocess authenticates natively, allowing Claude to refresh its own login during execution. No copied token is ever forwarded by OpenClaw on this path. If the host login is absent or belongs to a different account, the run stops before spawning and prints the exact re-authentication commands. Credentials managed by OpenClaw, such as Anthropic OAuth login profiles, setup tokens, and API keys, are still passed directly to the subprocess and refreshed by OpenClaw where applicable.

The gateway service needs to resolve claude on PATH. Deployments requiring a nonstandard executable path should register a wrapper via a CLI backend plugin.

Manual token entry

Provider-agnostic; it writes the per-agent SQLite auth store and updates the configuration:

openclaw models auth paste-token --provider openrouter

Each agent's openclaw-agent.sqlite is where OpenClaw reads auth profiles from. Endpoint details, including baseUrl, api, model ids, headers, and timeouts, belong under models.providers.<id> in openclaw.json or models.json, rather than inside auth profiles.

For older installations still carrying auth-profiles.json, auth-state.json, or a flat layout such as { "openrouter": { "apiKey": "..." } }, running openclaw doctor --fix imports that data into SQLite. Doctor keeps timestamped backups next to the original JSON files.

External auth routes, like Bedrock's auth: "aws-sdk", are not credentials. For a named Bedrock route, auth.profiles.<id>.mode: "aws-sdk" should be set in openclaw.json, and type: "aws-sdk" should not be written into the auth profile store. Legacy AWS SDK markers are migrated from the credential store into config metadata by openclaw doctor --fix.

SecretRef-backed credentials

  • Credentials for api_key may use keyRef: { source, provider, id }
  • Credentials for token may use tokenRef: { source, provider, id }
  • Profiles running in OAuth mode reject SecretRef credentials: when auth.profiles.<id>.mode is "oauth", a SecretRef-backed keyRef/tokenRef for that profile is refused.

Checking model auth status

openclaw models status
openclaw doctor

A check suited for automation, returning 1 when expired or missing and 2 when nearing expiry:

openclaw models status --check

Live authentication probes (add --probe-provider, --probe-profile, --probe-timeout, --probe-concurrency, or --probe-max-tokens to limit the scope):

openclaw models status --probe

Notes:

  • Probe rows may originate from auth profiles, environment credentials, or models.json.
  • When auth.order.<provider> lacks a stored profile, the probe returns excluded_by_auth_order for that profile instead of attempting it.
  • If auth is present but OpenClaw cannot identify a probeable model for that provider, the probe yields status: no_model.
  • Cooldowns tied to rate limits can apply per model: a profile cooling down for one model may still handle a sibling model on the same provider.

Optional ops scripts (systemd/Termux): Auth monitoring scripts.

API key rotation (gateway)

Certain providers retry a request using a different configured key when a provider rate limit is encountered.

Key priority order for each provider:

  1. OPENCLAW_LIVE_<PROVIDER>_KEY (a single override that locks in one key)
  2. <PROVIDER>_API_KEYS (a list separated by commas, spaces, or semicolons)
  3. <PROVIDER>_API_KEY
  4. <PROVIDER>_API_KEY_* (any environment variable carrying this prefix)

Google providers (google, google-vertex) also fall back to GOOGLE_API_KEY. The assembled list gets deduplicated prior to use.

OpenClaw advances to the next key only when the error message matches: rate_limit, rate limit, 429, quota exceeded/quota_exceeded, resource exhausted/resource_exhausted, or too many requests. Other errors skip alternate-key retries. When every key fails, the error from the final attempt is returned.

Note

Provider-specific wording like ThrottlingException, concurrency limit reached, or workers_ai ... quota limit exceeded governs failover/retry classification (switching models or providers after repeated failures), which is a separate process from the API-key rotation described above.

Deleting saved auth does not invalidate the key at the provider. To revoke provider-side, rotate or revoke the key through the provider dashboard.

Removing provider auth while the gateway is running

When provider auth is removed via the gateway control plane, OpenClaw erases the saved auth profiles for that provider and terminates active chat/agent runs whose selected model provider matches the removed one. Terminated runs emit the standard cancellation/lifecycle events with stopReason: "auth-revoked", letting connected clients indicate the run stopped because credentials were removed.

Controlling which credential is used

OpenAI and legacy openai-codex ids

OpenAI API-key profiles and ChatGPT/Codex OAuth profiles share the canonical provider id openai. Use openai:* profile ids and auth.order.openai for new configuration.

If openai-codex shows up in older config, auth profile ids, or auth.order.openai-codex, treat it as legacy migration input. Do not create new openai-codex profiles. Execute:

openclaw doctor --fix
openclaw models auth list --provider openai

Doctor rewrites legacy openai-codex:* profile ids and auth.order.openai-codex entries to the canonical openai route. For OpenAI-specific model/runtime routing, refer to OpenAI.

During login (CLI)

openclaw models auth login --provider openai --profile-id openai:ritsuko
openclaw models auth login --provider openai --profile-id openai:lain

--profile-id keeps multiple OAuth logins for the same provider distinct within a single agent.

--force removes the saved auth profiles for that provider in the chosen agent directory, then reruns the same auth flow. Use this when a saved profile is stuck, expired, or bound to the wrong account. It does not revoke credentials at the provider.

openclaw models auth login --provider anthropic --force

Per-session (chat command)

  • /model <alias-or-id>@<profileId> -s locks a specific provider credential for the current session (example profile ids: anthropic:default, anthropic:work).
  • /model (or /model list) displays a compact picker; /model status shows the full view (candidates plus the next auth profile, along with provider endpoint details when set).

Modifications to auth.order alter how profiles are chosen automatically. Both /new and /reset remove auto-selected fallback or rotation state, yet any valid explicit user model or profile pin remains intact; to replace a user profile pin, pick a different explicit @profile selection.

Per-agent (CLI override)

Overrides for auth order live in that agent's SQLite auth state:

openclaw models auth order get --provider anthropic
openclaw models auth order set --provider anthropic anthropic:default
openclaw models auth order clear --provider anthropic

Point to a particular agent with --agent <id>; if you leave it out, the configured default agent is used. openclaw models status --probe displays omitted stored profiles as excluded_by_auth_order instead of quietly ignoring them.

Troubleshooting

"No credentials found"

On the gateway host, set an Anthropic API key or follow the Anthropic setup-token route, then verify again:

openclaw models status

Token expiring/expired

Run openclaw models status to identify which profile is about to expire. When an Anthropic token profile is absent or has lapsed, refresh it through setup-token or switch to an Anthropic API key.

1,510 words · updated Aug 13, 2026