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 --probeopenclaw doctorauth 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:
reasonCode | Meaning |
|---|---|
excluded_by_auth_order | Profile omitted from the explicit auth order for its provider. |
missing_credential | No inline credential or SecretRef is configured. |
expired | Token expires is in the past. |
invalid_expires | expires is not a valid positive Unix ms timestamp. |
unresolved_ref | Configured SecretRef could not be resolved. |
ineligible_profile | Profile is incompatible with provider config (includes malformed key input). |
no_model | Credentials 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
- A token profile is ineligible when both
tokenandtokenRefare absent (missing_credential). expiresis optional. When present it must be a finite number of Unix epoch milliseconds greater than0and no larger than the maximum JavaScriptDatetimestamp (8640000000000000).- If
expiresis invalid (wrong type,NaN,0, negative, non-finite, or beyond that maximum), the profile is ineligible withinvalid_expires. - If
expiresis in the past, the profile is ineligible withexpired. tokenRefdoes not bypassexpiresvalidation.
Resolution rules
- Resolver semantics match eligibility semantics for
expires. - For eligible profiles, token material may be resolved from the inline value or
tokenRef. - Unresolvable refs produce
unresolved_refinmodels status --probeoutput.
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: falseapplies,api_keyandtokenprofiles can be moved between environments. - By default,
oauthprofiles lack portability, since refresh tokens may be single-use or sensitive to rotation. - Provider-owned OAuth flows can enable
copyToAgents: trueonly 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 --probeprobes only profile ids still present in that provider's resolved auth order. The stored override takes precedence overauth.orderconfig. - 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_orderand the detailExcluded 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(resultsource:profile,env,models.json). - If a provider has credentials but OpenClaw cannot resolve a probeable model candidate for it,
models status --probereportsstatus: no_modelwithreasonCode: no_model.
External CLI credential discovery
- Runtime-only credentials owned by external CLIs (Claude CLI for
claude-cli, Codex CLI foropenai, MiniMax CLI forminimax-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:
nonefor persisted or plugin auth only,existingfor refreshing already stored external CLI profiles, orscopedfor 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>.modeequals"oauth", SecretRef-backedkeyRef/tokenRefinput 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]: ....