OpenClaw EnterpriseDOCSGitHub

Harness Authentication Binding Flow

Overview

Select an OCC Secret or ChatGPT account credential through Agent harnessAuth. Deployment freezes the authorized binding; the worker rechecks it and Kubernetes renders the credential only into the model-executing workload, which authenticates before guarded activation. SSH runtime binds operator credentials and checks gateway readiness without model authentication.

Codex OAuth device login through an external credential source is Experimental; see the launch limits.

Entry Points

Flow

graph TD
  A["Store key or separately issue account credential"] --> B["Save Agent harnessAuth reference"]
  DA["Refresh Driver completes device login"] -.-> B
  G -->|external ChatGPT| OA["Sandbox supplies placeholder<br/>and account metadata"]
  OA --> J
  R["Operator provisions protected host env"] --> B
  D -->|runtime| S["SSH starts embedded gateway using host env"]
  S --> T["Check gateway readiness; model auth remains unverified"]
  B --> C["Authorize and freeze binding in Agent revision"]
  C --> D["Worker rechecks grants and source ownership"]
  D -->|denied or changed source| E["Reject candidate before projection"]
  D -->|valid managed source| F["Kubernetes prepares explicit login mode and projections"]
  F --> G{"Admitted topology"}
  G -->|embedded API key| H["Create or replace shared gateway with projected key"]
  G -->|dedicated key or account| I["Only Codex receives model credential"]
  I --> J{"Login and primary model turn succeed?"}
  J -->|first model subprocess timeout| P["Wait one second within startup budget"]
  P --> Q{"Second model probe succeeds?"}
  Q -->|yes| L
  Q -->|no| K["Candidate remains unready"]
  J -->|login or nonretryable failure| K
  J -->|yes| L["Runtime readiness and guarded activation"]
  H --> M{"Native primary model probe succeeds?"}
  M -->|no| N["Gateway stays unready; replacement may interrupt service"]
  M -->|yes| O["Gateway becomes ready; complete activation"]

Execution Trace

1. Acquire or select one credential source

packages/occ/src/index.ts:OpenClawController.startAgentDeviceAuthorization, pollAgentDeviceAuthorization, cancelAgentDeviceAuthorization

Device login creates a credential source and asks its Credential Refresh Driver to start and poll authorization. The Secret-backed session records actor, exact Namespace and optional Agent scope, source identity, and an opaque Refresh Driver handle. The Refresh Driver hands the provider grant to the external service. Ready responses return a credential-source reference; Console saves a credential_source binding and grants the Agent principal exact source operate.

Secret compare-and-swap permits one in-flight poll and fences cancellation. An uncertain exchange requires reconnect. Closing or expiring a session removes its handle without revoking the source. Plugin discovery uses the Gateway's withSourceToken callback with current source authorization; the service may refresh before returning a usable access token. It continues through the saved source after the login session closes.

Console calls apps/controller/src/drivers/compute/model-discovery.ts:discoverHarnessModels without storing credentials. OpenAI API-key discovery excludes models with a valid shutdown_date today or earlier in UTC; other dates and the Anthropic and service-account catalogs remain unfiltered. Discovery does not prove a model call.

packages/occ/src/index.ts:OpenClawController.createAgent, updateAgent, authorizeHarnessAuthSource

Create and PATCH follow the harnessAuth field semantics. API keys and imported codex_pat tokens use stable OCC Secret references and require exact Secret operate. Managed PATs use ServiceAccount references and require exact account read. OAuth uses a CredentialSource reference owned by the selected Credential Gateway and requires exact source operate. Namespace locks serialize source reference changes against deletion. Missing or foreign sources fail closed. Binding never selects a different model, Backend, Harness, or execution mode and cannot issue an account credential.

The Secret storage flow owns value storage; account issuance owns upstream credentials and their private Backend binding.

2. Freeze the admitted source and compatibility

packages/occ/src/index.ts:OpenClawController.deployAgent, admitHarnessAuth

Deployment requires a nonnull binding, exact Agent deploy, and Configuration read. For a key or service account token, OCC checks the actor's and Agent principal's exact Secret operate, resolves the backend through the selected Secret Driver, and freezes the stable reference and Driver identity. For a ChatGPT account, it verifies the issued access-token reference and private Backend, member Driver, and workspace ownership. runtime needs no source grant, lookup, or delivery metadata. The selected Compute validates the combination: SSH accepts only embedded OpenClaw with runtime. Kubernetes validateHarnessAuth requires dedicated Codex for both imported and managed codex_pat sources. External ChatGPT sources require dedicated Codex and the paired Sandbox and Credential Gateway. Deployment and guided provisioning reject unsupported combinations before admitting work or stopping predecessors.

Host credential changes can affect a runtime version after restart without redeployment; see the SSH lifecycle.

The Agent revision contains references and safe internal metadata, never credential bytes. Public serialization exposes the binding but omits backend locators and private account ownership. A later account credential cannot replace the admitted reference; draft changes affect only the next explicit deployment.

3. Recheck authorization before provisioning the Agent revision

apps/controller/src/worker.ts:ControllerWorker.resolveRevisionBackend, resolveRevisionSecretContext

The worker authorizes the original deploying actor and required Agent Secret grants for the saved version, checks source ownership, and matches managed-account credential and Backend metadata against the frozen snapshot. Revocation or a changed source rejects work before provisioning. For runtime, only Agent/Configuration authorization runs; the dispatch context carries only the method, and SSH neither reads the operator credential file nor issues a model probe.

For an API key or directly supplied service account token, the worker resolves backend ownership from OCC state and passes an ephemeral ComputeRevisionContext without reading credential bytes or rewriting the Agent revision. Compute then reads the canonical CP source, verifies the admitted Secret UID or managed-account ownership, and delivers only selected fields into the DP Secret for that Agent revision. Missing or replaced sources fail preparation. Managed ChatGPT accounts retain the exact token source; their private Backend binding owns workspace metadata. Previous versions keep references without retaining their sources indefinitely; drafts, selected versions, and pending deployments block source deletion.

4. Prepare and place the one credential projection

apps/controller/src/drivers/compute/kubernetes/index.ts:prepareHarnessAuth, KubernetesComputeDriver.prepareRevision

For credential_source, KubernetesComputeDriver.admittedCredentialSourceType checks the saved Credential Gateway ID before querying its current type catalog in preparation and runtime activation. A replacement Gateway receives no catalog call. The existing Harness authentication validator refuses the mismatch and still checks the source type, login mode, and paired Sandbox. Catalog lookup passes only an abort signal; it does not read or send a credential.

Compute projects the admitted Secret into the combined embedded workload as OPENAI_API_KEY, ANTHROPIC_API_KEY, or, for explicit custom providers, OCE_MODEL_API_KEY. harnessModelAuthentication and requireProviderApiKeys require a matching provider key reference. Configuration environment and generic Secret bindings cannot override it. All selections retain the same provider. harnessProbeConfiguration preserves custom transport/model IDs and supplies a default env SecretRef; native probe results must name models.json for this path, env for built-ins. Dedicated Codex receives only its key or CODEX_ACCESS_TOKEN; its Gateway receives neither. Initial runtime credentials supply transport/channel groups, not model authentication.

The selected Sandbox consumes these already-rendered HarnessWorkloadRequirements and selects or looks up no other credential. An upstream runtime unable to honor genuine Secret projection fails explicitly. Network policies keep the provider-login egress the admitted auth method requires. Gateway transport and Kubernetes workload identity credentials stay separate.

5. Authenticate during runtime startup

apps/controller/src/drivers/compute/kubernetes/runtime-entrypoints.ts:AGENT_RUNTIME_ENTRYPOINT, GATEWAY_RUNTIME_ENTRYPOINT

Codex consumes explicit CODEX_LOGIN_MODE: API-key login receives the key through stdin; managed and directly supplied service account tokens both use codex_pat and --with-access-token. Native whoami validates and hydrates identity from the token, without a runtime workspace override. Credential environment variables are deleted before the probe and app-server start. Missing or conflicting inputs, failed login, or a failed primary-model probe (under the restricted probe policy) prevent app-server startup and readiness. API-key and service-account login state remains in the temporary home. Its volume has a 1Gi size limit. External-token startup writes placeholder-only auth state instead of running native login (step 6).

The dedicated wrapper retains APP_SERVER_TOKEN for local plugin authentication (with plugin status enabled, deriving it from the Agent revision and startup identity) but omits it from the codex login and codex app-server environments; the listener receives the current token's SHA-256 digest. The token remains in the Pod; filtering child environments does not isolate same-UID processes.

startAuthenticatedCodex gives probeCodexAuthentication at most two attempts within one monotonic 61-second budget. Only a subprocess ETIMEDOUT schedules the second, after a one-second timer, timed out at the smaller of 30 seconds and the remaining budget; an unexplained SIGKILL is nonretryable.

Embedded OpenClaw consumes the selected provider's native API key and runs one native primary-model probe during actual gateway startup, with tools and fallback disabled; its 256-token output cap lets reasoning models answer within the 15-second timeout. Initial and replacement deployments use the same path; their Recreate activation can stop the serving gateway before the new process validates credentials, so a failure leaves the Agent unavailable until repair and restart or a new deployment, with no automatic rollback.

Both runtimes capture native output and hold final failures unready with a fixed message. Codex publishes the existing runtime failure only after retry exhaustion or a nonretryable result. Readiness polling does not repeat provider calls. A restart or deployment starts a new check with the same timeout. Probes may incur usage charges.

After readiness, the activation and recovery flow completes activation. Updating a Secret leaves existing process environments and DP runtime copies unchanged until preparation: deploy each consumer, verify a real turn, then revoke the previous key upstream. Version history cannot restore historical Secret values.

6. Deliver externally managed OAuth authentication

apps/controller/src/drivers/compute/kubernetes/index.ts:credentialSourceEnvironment, apps/controller/src/drivers/compute/kubernetes/runtime-entrypoints.ts:AGENT_RUNTIME_ENTRYPOINT

Compute checks that the returned attachments match the authorized sources exactly, with no missing, duplicate, or unexpected source IDs, before provisioning the Sandbox. It selects the attachment named by harnessAuth.sourceId for the Codex placeholder and trusted account metadata, and passes every attachment to the Sandbox. Attachment order does not select Harness authentication.

Compute sends the placeholder and account metadata only to the Harness. Its launcher writes ephemeral chatgptAuthTokens auth state without a refresh token and runs the normal native probe before app-server startup. The external service retains refresh ownership; the paired Sandbox injects a warm access token into authorized outgoing requests. There is no native-refresh or persistent-bundle fallback. Restarts reconstruct the same receiving state from a current attachment; sessions and workspace keep their independent persistence.

After withdrawal, OpenShell omits the credential binding when the same Sandbox restarts. OPENSHELL_CHATGPT_AUTH_BOOTSTRAP lets that absence reach the Harness launcher, which holds AUTHENTICATION_FAILED at the login phase through its authenticated status endpoint. The process stays alive and unready; it does not write auth state, start Codex, or use an earlier auth file. A present but malformed binding still fails the bootstrap check. Recovery requires a new authorized deployment, as described in the withdrawal reference.

The credential source lifecycle owns source registration, authorization, withdrawal and deletion. The experimental OpenShell source uses the paired Refresh Driver and upstream Gateway/Sandbox integration described in the Driver reference.

Debugging and Verification

Search documentation