CredentialGatewayDriver contract
Overview
CredentialGatewayDriver holds credentials outside the Agent workload and
applies them to the Agent's outbound requests. OpenClaw Control Plane (OCC) owns
the credential source record, its Secret references,
authorization, and Agent bindings. The Driver owns the stored copy of the value,
the source-type catalog, and how a credential reaches a request. The paired
SandboxDriver consumes the Driver's attachments for each Agent revision when
it creates the Harness, and Compute waits for those attachments
before activation.
Selection is optional. The only implementation is the bundled
OpenShell Credential Gateway, which requires
the bundled Kubernetes Compute Driver, the bundled OpenShell SandboxDriver, and
an openshell Backend that declares both. See
Driver selection.
When a Credential Gateway is selected, it replaces Secret-backed model delivery. Agents must authenticate their Harness through a credential source; there is no fallback to environment delivery.
Interface
Core interface
The shared interface requires every method below. Startup rejects a Driver that omits one.
| Operation | Inputs and preconditions | Result or side effects | Failure or absence |
|---|---|---|---|
listSourceTypes |
Cancellation signal. | The implementation's catalog of CredentialSourceType entries. |
OCC treats a failure as dependency unavailable. |
validateSourceConfig |
Catalog-checked type and nonsecret configuration. | Synchronous validation without I/O, Secret reads, or persistence. | Invalid values throw CredentialSourceConfigError (400). |
registerSource |
Ready Namespace, the new source record, and resolved Secret values; none for a refresh type. |
Stores the value in the gateway and returns ready, pending, failed, or absent. |
failed or absent fails registration; OCC then calls removeSource. |
updateSource |
Existing source and new resolved values. | Replaces the stored values for processes started afterwards and returns the source state. | failed or absent fails the update; OCC keeps the Secret references unchanged. |
sourceStatus |
Existing source. | Live source state and an optional safe reason. | OCC reports failed with a fixed reason when the call throws. |
removeSource |
Source record. | Deletes the stored copy. An already-absent source counts as removed. | A failure leaves the OCC record deleting for retry. |
attachForRevision |
Namespace, Agent revision, and the bound source records. | Exactly one { sourceId, ref } attachment per bound source. ref is opaque to OCC. |
Throws when a source is unavailable or foreign; the Agent revision does not provision. |
attachmentStatus |
The same context plus the provisioned SandboxResourceRef. |
Per-source state: ready, pending, withheld, failed, revoked, or absent. |
Compute blocks activation on any state other than ready or pending. |
withdraw |
Placement, Agent revision, its required SandboxResourceRef, and one source ID; no source list. |
Revokes that Agent revision's access, including running processes. revoked only on gateway evidence, absent when the Sandbox is gone, otherwise pending. |
Anything but revoked or absent keeps the OCC withdrawal pending for retry. |
validateSourceConfig({ type, config }) checks nonsecret values synchronously,
without network calls or other effects. OCC calls it after catalog field checks,
before reading Secrets or creating a record. It may return the configuration
with the same fields in the form the gateway uses, such as a normalized URL;
OCC then stores and registers that instead of the written values. Invalid values throw
CredentialSourceConfigError with a safe field name and message; HTTP reports
400 INVALID_REQUEST. Do not include submitted values in the error.
attachForRevision throws CredentialSourceRevisionError when two sources would
share a placeholder environment variable; the worker then fails the deployment
at once instead of retrying.
A CredentialSourceType declares:
type: an implementation-defined name, such asopenai.configandsecrets: field specifications withname,required, and an optional description.configfields are nonsecret strings;secretsfields are supplied as OCC Secret references.issuerRotated: truemarks a secret the issuer replaces on use, such as a rotating refresh token; an update must reference a new Secret for it.rotation:none,external, orrefresh. Arefreshtype stores no static value. The Credential Refresh Driver on the same Backend mints and refreshes its tokens; OCC calls that Driver to change their material. Secret-backed types accept updates; device-authorized types require a new login source instead.deviceAuthorization: optional{ harnessId }declaring device login for this source type. The login path requires one matching type with no required user config or Secret inputs.harnessAuth: optional{ modelProvider, loginMode }. Only a type with this entry can authenticate a Harness. Login modes areapi_keyand, for dedicated Codex,codex_patorchatgptAuthTokens. An Agent lists every source it uses, of any type, incredentialSources.
External ChatGPT authentication
The chatgptAuthTokens mode receives externally managed ChatGPT authentication
through a credential source. It is a receiving contract for a Credential
Gateway and paired Sandbox that already provide OAuth token injection. The
experimental OpenShell codex-oauth type requires the upstream gateway API and
alias-enabled supervisor described in the OpenShell Driver reference.
For an OAuth attachment used by a managed request guard, requestScope carries
the provider’s host, port, path and configured OAuth scopes to the paired Sandbox.
The Sandbox uses these non-secret limits when it prepares the revision’s request policy.
For an openai/chatgptAuthTokens source, attachForRevision must return
externalChatgptAuth on the source's attachment: accessTokenPlaceholder,
accountId, planType, and optional userId, accountUserId, email, and isFedramp. The
trusted Driver supplies account metadata from the authenticated connection;
these fields are not caller-selected Agent configuration. The placeholder must
be the exact value recognized by the egress injector. Real access tokens,
refresh tokens, and the original ID token stay outside the Harness.
Compute validates one attachment per authorized source and selects the Codex
attachment by harnessAuth.sourceId, independently of attachment order. It passes
every attachment to the Sandbox and the selected placeholder and account metadata
to the dedicated Codex entrypoint. The entrypoint writes an ephemeral auth.json
with auth_mode: "chatgptAuthTokens", the unchanged access-token placeholder, an
empty refresh token, and a synthetic ID-token payload containing the account
metadata. Native Codex uses that metadata for account identity, plan and
workspace decisions. This external mode does not run native OAuth refresh;
the existing native model probe must still succeed before app-server starts.
The external credential service owns refresh and the gateway owns injection for inference, hosted app/MCP, and authenticated account/configuration requests. Metadata is projected at provisioning; account metadata changes require a new Agent revision. A fresh device login creates a new source for explicit replacement. Native user-identity checks that depend on access-token claims are not established with an opaque placeholder.
This replaces the legacy runtime-owned OAuth binding. No persistent credential bundle or native-refresh fallback is supported. See Experimental OAuth storage.
Optional additions
Device-login source types require the paired Credential Refresh Driver to implement authorization. The Gateway registers the source before login and owns its attachment. It receives no device-grant refresh material.
The trusted bundled OpenShell Backend reader performs ordinary metadata lookup
and operator-mTLS export for plugin discovery. An external Credential Gateway
retains the optional withSourceToken(context, use) callback. Both paths require
the same exact Gateway owner match and Namespace checks; neither falls back to
another Gateway or tenant. The bundled reader does not take over refresh.
withSourceToken(context, use) supplies a usable CredentialSourceToken only for
an authorized configuration callback: access token and optional trusted account
ID/FedRAMP classification. The external token service may refresh to satisfy its
remaining-lifetime requirement. It owns refresh credentials, refresh execution,
and successor-token persistence; this operation must never return refresh
material. OCC does not implement refresh or retain the returned access token
outside the callback.
OCC checks authorization, source readiness, attachment where required, and the selected catalog before retrieval, then rechecks before catalog dispatch. Cancellation or a failed recheck does not undo refresh already started by the external service. Source withdrawal and token readiness remain that service's responsibility.
SecretDriver.withValue supplies static registration inputs. Withdrawal also
uses Compute's withdrawCredentialSource and the Sandbox's harnessResource,
which returns the Sandbox for the Agent revision ID without side effects.
Compute throws CredentialWithdrawalRefusedError when its configuration cannot
reach that Sandbox or it finds an object it does not own; the worker then fails
the withdrawal without retrying.
IAM
The selected IAM Driver authorizes every OCC operation before the Driver is called:
- Registration requires
credential_source:createon the Namespace andsecret:operateon every referenced Secret. OCC reads Secret values only after those checks. - Binding a source to an Agent requires the caller's
credential_source:operateon the exact source, including the current source when PATCH replaces or clears it. - Deployment admission and the worker require
credential_source:operatefor both the deploying actor and the Agent's service principal. The Agent principal needs no permission on the underlying Secret.
The Driver receives only authorized, exact-Namespace sources. It must never log, return, or persist a secret value outside its own credential store. OCC never stores the value, and Agent revisions and audit records carry only the source ID. Gateway credentials, such as the OpenShell Backend's bearer token, are separate from OCC authority; see Permissions.
Lifecycle
The Driver is constructed at API and worker startup from trusted Installation configuration. The interface has no initializer or destructor.
- Registration. The API validates the request against
listSourceTypes: unknown types, unknown fields, and missing required fields fail before any gateway write. The Driver validates configuration values withvalidateSourceConfigbefore any Secret read or persistence. Compute'sresolveSandboxNamespacesupplies the Namespace's runtime placement, which the gateway shares with the paired Sandbox. The API reads each Secret value and commits the record asregistering, then callsregisterSourceoutside the transaction. A second transaction moves the record toreadywith its audit event. For arefreshtype, the Credential Refresh Driver first mints a token; device-authorized types defer that step until login completion. IfregisterSourcereturnsfailedorabsent, OCC callsremoveSourceand deletes the record. If it throws, a create may still land, so OCC callsremoveSourcebut keeps the recorddeleting. OCC finalizes a deletion only 70 seconds aftercreatedAt, and a Driver must finish every effect of an aborted registration within 30 seconds of the abort. A record leftregisteringordeletingis never usable, and the caller retries DELETE to remove any gateway copy. See credential sources. - Admission.
deployAgentfreezes{ method, sourceId, credentialGatewayId, sourceType, loginMode }in the Agent revision. The source must beready, and its type must declareharnessAuth. A Sandbox must be selected, and Compute validates the combination; see Harness authentication. Every listed source, including the Harness source, is frozen as{ sourceId, credentialGatewayId, sourceType }incredentialSources. - Dispatch. The worker rechecks both
operategrants, requires the selected gateway to match the snapshot, and loads the current source record. A missing,deleting, or mismatched source stops the Agent revision. Compute revalidates the binding against the gateway's current catalog entry. The worker passes the other listed sources it loaded inComputeRevisionContext.credentialSources, omitting the Harness source and any withdrawn from the Agent revision. - Provisioning. Compute calls
attachForRevisionwith the Harness source first and the other sources after it, and passes the result inHarnessWorkloadRequirements.credentialAttachmentstoprovisionHarness. The Credential Gateway issues one reference per bound source. Its paired Sandbox must consume every attachment and reject references from any other provider. - Activation. After the Harness is ready, Compute calls
attachmentStatus.pendingor a missing status retries reconciliation;failed,withheld,revoked, orabsentfails it. Onlyreadyfor every attachment lets the Agent revision activate. - Update. The API locks the source, reads its current or replacement Secret
values, and calls
updateSource. Running Harness processes keep the previous value until they restart. - Withdrawal. The API records a
pendingwithdrawal for the currently selected Agent revision and queues worker work. The worker rechecksagent:operate, and Compute derives the Sandbox from the Agent revision ID and callswithdrawfor each pending withdrawal of the Agent revision. Onlyrevokedorabsentmarks onerevoked; otherwise the work retries. The Agent revision never re-attaches a withdrawn source. Because a Sandbox create accepted before a withdrawal can land after it, each preparation, and each maintenance pass of an Agent revision whose Harness source is withdrawn, first callswithdrawwithrecheckfor everyrevokedsource of the Agent revision: the gateway then detaches only a source the Sandbox still lists. - Deletion. The API refuses deletion while an Agent draft, currently selected Agent revision,
or pending deployment references the source. Otherwise it marks the record
deleting, callsremoveSource, then deletes the record. Agent revision stop and retirement remove attachments with the Sandbox. A failed Sandbox cleanup leaves the stop or retirement pending for retry.
Registration and removal must be idempotent for one source ID so that retries adopt or delete the same stored copy.
Limits
- One Credential Gateway can be selected per Installation, and it must belong to a configured Backend.
- Rotation belongs to the Credential Refresh Driver. Update pushes new static values; running Agents use them after a redeploy.
- Compute accepts
openai/api_keycredential sources for dedicated Codex or native OpenClaw.openai/chatgptAuthTokensis dedicated-Codex-only and requires the external-auth attachment described above. The bundled catalog includes experimental Codex device login through the paired Refresh Driver. Other listed sources need a Sandbox Driver that provisions the Harness. - Guided Agent provisioning rejects credential-source Harness authentication. Create the Agent, then deploy it.
- Installed Credential Gateway packages are unsupported.
Troubleshooting
| Symptom | What to check |
|---|---|
Registration returns 400, 404, or 409 |
Compare the type and field names with the Driver catalog, and confirm each Secret belongs to the same Namespace. |
Registration or binding returns 403 |
Check credential_source:create or operate, and secret:operate on each referenced Secret. |
Deployment returns 409 with a gateway selected |
Change harnessAuth to credential_source. Secret-backed and account methods are rejected while a gateway is selected. |
Registration or deletion returns 503, or a read reports failed |
Check gateway connectivity and credentials. Retry deletion; the record stays deleting until the stored copy is removed. |
503 naming the driver that registered the source |
Another driver is selected; see After a Credential Gateway change. |
| An Agent revision never activates | Check the worker's reason code and the source's live status. A failed attachment state requires repairing the gateway source. |
Implementations
- OpenShell Credential Gateway: bundled; stores sources as OpenShell providers and injects them at the Sandbox egress proxy.
