OpenClaw EnterpriseDOCSGitHub

CredentialRefreshDriver contract

Overview

CredentialRefreshDriver mints and re-mints the tokens of refresh-type credential sources. A refresh type, such as an OAuth2 client-credentials source, has an issuer and long-lived refresh material, such as a client secret or refresh token. The Driver holds that material, obtains an access token from the issuer, and obtains a new one before it expires. The Agent keeps the same placeholder throughout, so running processes need no restart.

OpenClaw Control Plane (OCC) owns the source record, its Secret references, and authorization. The paired Credential Gateway owns the source's stored record and applies the current token to the Agent's requests. This Driver owns issuer exchange, refresh material, and minted tokens. OCC calls it for setup, device authorization, incident rotation, status, and removal. Configuration discovery uses the Gateway's access-token callback; OpenShell may refresh during retrieval without an OCC refresh call.

Selection is optional. The only implementation is the bundled OpenShell Credential Refresh, which must belong to the same openshell Backend as the selected Credential Gateway. See Driver selection. Without it, the gateway's catalog offers no refresh types.

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
configureRefresh A source the gateway registered, its config, resolved refresh material, and a UUID request ID. Replaces the source's refresh material. Replaying a successful request ID applies nothing new. A throw leaves the outcome unknown; OCC never retries it with a new request ID.
rotate A configured source and a UUID request ID. Forces one mint and returns the refresh status. It does not revoke the old token at the issuer. Only ready confirms a usable minted token.
refreshStatus An existing source. Current refresh status. Missing state is pending before device authorization, otherwise failed.
removeRefresh Source record. Deletes the stored refresh material. Already-absent material counts as removed. A throw keeps the OCC record deleting for retry.

CredentialRefreshStatus carries only state (pending, ready, or failed), the token's expiresAt, nextRefreshAt, and lastRefreshAt times, an implementation-owned failureCode, and a recoveryAction of retry, reauthorize, fix_configuration, or investigate. It never carries a token, refresh material, or text from the issuer.

A CredentialSourceType whose rotation is refresh needs this Driver. The four refresh methods are required; device authorization adds optional hooks.

Device authorization

A type declaring deviceAuthorization.harnessId requires this Driver's startDeviceAuthorization(context) and pollDeviceAuthorization(context, privateState). OCC first registers an empty source with the Gateway; it defers refresh setup until authorization supplies a grant. Start returns device instructions and an opaque handle. Poll returns pending or ready only, never issuer credentials. The Refresh Driver performs the exchange, configures gateway-owned refresh, and confirms a usable token before reporting ready.

OCC fences polling with Secret compare-and-swap and binds the session to its actor, source, and both Gateway and Refresh Driver IDs. It rechecks those bindings and authority after external completion. A changed selection or uncertain exchange requires reconnecting; it never replays the exchange. Closing the session removes only its handle. Existing sources remain usable by their authorized Agents. Device-source PATCH is refused: create a new login source rather than reseeding a rotating refresh grant.

IAM

The selected IAM Driver authorizes each OCC operation before the Driver is called:

The Driver receives only authorized, exact-Namespace sources. It must never log, return, or persist refresh material or tokens outside its own store. Issuer credentials belong to the source, not to OCC.

Lifecycle

The API and worker construct the Driver at startup from trusted Installation configuration; only the API calls it. The interface has no initializer or destructor.

  1. Registration. OCC calls the gateway's registerSource with config only; resolved Secret values go only to this Driver. After it succeeds, OCC calls configureRefresh and then rotate to mint the first token. Both request IDs derive from the source ID, so a replay of the same step is not applied twice. The source becomes ready only once rotate reports ready. On any failure, OCC calls removeRefresh and the gateway's removeSource, as for a failed static registration. Device-authorized types register without configuring or minting; their first mint occurs during the device completion above.
  2. Background refresh. The Driver re-mints before expiry without OCC. A failure appears in the source's status with its recovery action.
  3. Update. PATCH reads the current or replacement Secret values and calls configureRefresh, then rotate. OCC commits replacement Secret references only after a ready mint. The update is not atomic: after configureRefresh succeeds, a failed mint returns 503 but the Driver keeps the new material, and the source stays ready with the failure in its status. OCC restores nothing; supply corrected Secrets. An update must name a different Secret for a catalog field marked issuerRotated, such as refresh_token, because the Driver may hold a newer value. On OpenShell, running Agents need a redeploy after any update that reaches configureRefresh; see its limits.
  4. Rotation. POST …/rotate calls rotate for incidents such as a suspected token leak. Running Agents keep their placeholder and need no redeploy.
  5. Status. Reading a source adds the Driver's refreshStatus to the gateway's status. A source whose type the catalog no longer offers keeps its gateway status without refresh status. Listing sources reads no status.
  6. Deletion. OCC calls removeRefresh, then the gateway's removeSource.

Limits

Troubleshooting

Symptom What to check
A refresh type is missing from the catalog Select drivers.credential_refresh and declare it on the gateway's Backend.
Registration or rotation returns 503 naming a failure code The issuer refused the material or was unreachable. Read the source's status.refresh and follow its recoveryAction.
status.refresh.recoveryAction is reauthorize The issuer revoked the refresh token. For a device source, reconnect with a new source. For a Secret-backed type, store new material in a Secret and PATCH its reference.
status.refresh.recoveryAction is fix_configuration Check the source's token_url, client_id, scope, and client secret against the issuer.
Rotation returns 409 The source is static. Update its Secret values instead.

Implementations

Search documentation