Auth Credential Semantics for Auth Profiles

Canonical rules for credential eligibility and resolution in auth profiles. Essential for developers working with resolveAuthProfileOrder, resolveApiKeyForProfile, or auth diagnostics.

Read this when

  • Working on auth profile resolution or credential routing
  • Debugging model auth failures or profile order

These semantics keep selection-time and runtime auth behavior aligned. They are shared by:

  • resolveAuthProfileOrder (profile ordering)
  • resolveApiKeyForProfile (runtime credential resolution)
  • openclaw models status --probe
  • openclaw doctor auth checks (doctor-auth)

Stable probe reason codes

Probe results carry a status bucket (ok, auth, rate_limit, billing, timeout, format, unknown, no_model) plus a stable reasonCode when the probe never reached a model call:

reasonCodeMeaning
excluded_by_auth_orderProfile omitted from the explicit auth order for its provider.
missing_credentialNo inline credential or SecretRef is configured.
expiredToken expires is in the past.
invalid_expiresexpires is not a valid positive Unix ms timestamp.
unresolved_refConfigured SecretRef could not be resolved.
ineligible_profileProfile is incompatible with provider config (includes malformed key input).
no_modelCredentials exist but no probeable model candidate resolved.

Eligibility checks report ok as the reason code for usable credentials.

Token credentials

Token credentials (type: "token") support inline token and/or tokenRef.

Eligibility rules

  1. A token profile is ineligible when both token and tokenRef are absent (missing_credential).
  2. expires is optional. When present it must be a finite number of Unix epoch milliseconds greater than 0 and no larger than the maximum JavaScript Date timestamp (8640000000000000).
  3. If expires is invalid (wrong type, NaN, 0, negative, non-finite, or beyond that maximum), the profile is ineligible with invalid_expires.
  4. If expires is in the past, the profile is ineligible with expired.
  5. tokenRef does not bypass expires validation.

Resolution rules

  1. Resolver semantics match eligibility semantics for expires.
  2. For eligible profiles, token material may be resolved from the inline value or tokenRef.
  3. Unresolvable refs produce unresolved_ref in models status --probe output.

Agent copy portability

Agent auth inheritance is read-through. When an agent has no local profile, it resolves profiles from the shared auth store at runtime without copying secret material into its own credential store (agents/<agentId>/agent/openclaw-agent.sqlite). The shared store lives in state/openclaw.sqlite after openclaw doctor --fix performs the one-time relocation. Until then, doctor reports the legacy agents/main/agent/openclaw-agent.sqlite owner and leaves that agent undeletable.

Explicit copy flows, such as openclaw agents add, use this portability policy:

  • Unless copyToAgents: false applies, api_key and token profiles can be moved between environments.
  • By default, oauth profiles lack portability, since refresh tokens may be single-use or sensitive to rotation.
  • Provider-owned OAuth flows can enable copyToAgents: true only when transferring refresh material across agents is proven safe; this opt-in works solely when the profile contains inline access and refresh material.

Profiles that are not portable stay reachable through the shared read-through base, unless the target agent logs in on its own and establishes a separate local profile.

Switching to temporary run state leaves the original shared-store root intact via openclaw agent exec. Its limited credential scope reads portable api_key and token profiles from that shared store without saving copies, while the configured agent's local profiles take precedence. Shared OAuth profiles fall outside this temporary scope, even with copyToAgents: true, so the run avoids gaining another refresh owner. --auth-env-only turns off stored credential access altogether.

Auth writes that explicitly pick a state directory, including isolated QA staging, rely on that directory's shared store for ownership and OAuth deduplication. Their runtime publication and rollback keep the same owner; a separate process-local state root does not serve as an inherited base. An unrelated outer database can be older, newer, or unreadable without halting an isolated write, yet an unreadable or newer database in the chosen target still fails closed. Writes without an explicit state directory keep the normal ambient state and agent-directory setup.

Config-only auth routes

Entries in auth.profiles carrying mode: "aws-sdk" act as routing metadata, not as stored credentials. They hold validity when the target provider uses models.providers.<id>.auth: "aws-sdk", the route written by the plugin-owned Amazon Bedrock configuration. These profile ids can show up in auth.order and session overrides even if the credential store has no matching entry.

Avoid writing type: "aws-sdk" into the credential store; stored credentials are limited to api_key, token, or oauth. When a legacy auth-profiles.json includes such a marker, openclaw doctor --fix relocates it to auth.profiles and strips the marker from the store.

Explicit auth order filtering

  • With auth.order.<provider> or the auth-store order override set for a provider, models status --probe probes only profile ids still present in that provider's resolved auth order. The stored override takes precedence over auth.order config.
  • A stored profile for that provider absent from the explicit order is not attempted later without notice. Probe output flags it with reasonCode: excluded_by_auth_order and the detail Excluded by auth.order for this provider.
  • A valid session user pin acts as an explicit per-session exception: OpenClaw tries that profile first even when omitted from the provider order, then falls back to the ordered same-provider profiles as retry candidates. A cooldown or disabled window affects only that profile; it does not block its eligible siblings.

Probe target resolution

  • Probe targets may originate from auth profiles, environment credentials, or models.json (result source: profile, env, models.json).
  • If a provider has credentials but OpenClaw cannot resolve a probeable model candidate for it, models status --probe reports status: no_model with reasonCode: no_model.

External CLI credential discovery

  • Runtime-only credentials owned by external CLIs (Claude CLI for claude-cli, Codex CLI for openai, MiniMax CLI for minimax-portal) are found only when the provider, runtime, or auth profile falls within the current operation's scope, or when a stored local profile for that external source already exists.
  • Auth-store callers pick an explicit external-CLI discovery mode: none for persisted or plugin auth only, existing for refreshing already stored external CLI profiles, or scoped for a concrete provider or profile set.
  • Read-only and status paths pass allowKeychainPrompt: false; they rely solely on file-backed external CLI credentials and never read or reuse macOS Keychain results.

OAuth SecretRef Policy Guard

SecretRef input applies to static credentials only. OAuth credentials change at runtime, since refresh flows persist rotated tokens, so SecretRef-backed OAuth material would split mutable state across stores.

  • When a profile credential is type: "oauth", SecretRef objects are rejected for any credential material field on that profile.
  • If auth.profiles.<id>.mode equals "oauth", SecretRef-backed keyRef/tokenRef input for that profile is rejected.
  • Violations cause hard failures, thrown as errors, in startup and reload secret preparation plus profile resolution paths.

Legacy-Compatible Messaging

To preserve script compatibility, probe errors keep this first line unchanged:

Auth profile credentials are missing or expired.

Human-readable detail and the stable reason code follow on later lines in the form ↳ Auth reason [code]: ....

1,129 words · updated Aug 28, 2026