Files
adolf/docs/plugins/admin-http-rpc.md
alvis bedb527145
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Vendor OpenClaw source as Adolf fork baseline
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11),
free to diverge. Tree copied sans upstream .git; upstream remote added for
future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19.
Preserves docs/ARCHITECTURE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
2026-07-05 09:36:54 +00:00

8.0 KiB

summary, read_when, title
summary read_when title
Expose selected Gateway control-plane methods through the bundled, opt-in admin-http-rpc plugin
Building host tooling that cannot use the Gateway WebSocket RPC client
Exposing Gateway admin automation behind a private trusted ingress
Auditing the security model for HTTP access to Gateway methods
Admin HTTP RPC plugin

The bundled admin-http-rpc plugin exposes an allowlisted set of Gateway control-plane methods over HTTP, for trusted host automation that cannot keep a Gateway WebSocket connection open.

It ships with OpenClaw but is disabled by default; when disabled, the route is not registered. When enabled, it adds POST /api/v1/admin/rpc on the same listener as the Gateway (http://<gateway-host>:<port>/api/v1/admin/rpc).

Enable it only for private host tooling, tailnet automation, or a trusted internal ingress. Never expose this route directly to the public internet.

Before you enable it

Admin HTTP RPC is a full operator control-plane surface: any caller that passes Gateway HTTP auth can invoke the allowlisted methods below. Enable it only when all of these are true:

  • The caller is trusted to operate the Gateway.
  • The caller cannot use the WebSocket RPC client.
  • The route is reachable only on loopback, a tailnet, or a private authenticated ingress.
  • You have reviewed the allowed methods and they match the automation you plan to run.

For OpenClaw clients and interactive tools that can keep a Gateway WebSocket connection open, use WebSocket RPC instead.

Enable

Enable the bundled plugin:

```bash openclaw plugins enable admin-http-rpc openclaw gateway restart ``` ```json5 { plugins: { entries: { "admin-http-rpc": { enabled: true }, }, }, } ```

The route is registered during plugin startup, so restart the Gateway after changing plugin config.

Disable it when you no longer need the HTTP surface:

openclaw plugins disable admin-http-rpc
openclaw gateway restart

Verify the route

Use health as the smallest safe request:

curl -sS http://<gateway-host>:<port>/api/v1/admin/rpc \
  -H 'Authorization: Bearer <gateway-token>' \
  -H 'Content-Type: application/json' \
  -d '{"method":"health","params":{}}'

A successful response has ok: true:

{
  "id": "generated-request-id",
  "ok": true,
  "payload": {
    "status": "ok"
  }
}

When the plugin is disabled, the route returns 404 because it is not registered.

Authentication

The plugin route uses Gateway HTTP auth.

Common authentication paths:

  • shared-secret auth (gateway.auth.mode="token" or "password"): Authorization: Bearer <token-or-password>
  • trusted identity-bearing HTTP auth (gateway.auth.mode="trusted-proxy"): route through the configured identity-aware proxy and let it inject the required identity headers
  • private-ingress open auth (gateway.auth.mode="none"): no auth header required

Security model

Treat this plugin as a full Gateway operator surface.

  • Enabling the plugin intentionally offers access to the allowlisted admin RPC methods at /api/v1/admin/rpc.
  • The plugin declares the reserved contracts.gatewayMethodDispatch: ["authenticated-request"] manifest contract, which is what lets its Gateway-authenticated HTTP route dispatch control-plane methods in process. This is not a sandbox: the contract prevents accidental use of reserved SDK helpers, but trusted plugins still run in the Gateway process.
  • Shared-secret bearer auth (token/password modes) proves possession of the gateway operator secret; narrower x-openclaw-scopes headers are ignored on that path and normal full operator defaults are restored.
  • Trusted identity-bearing HTTP auth (trusted-proxy mode) honors x-openclaw-scopes when present.
  • gateway.auth.mode="none" means this route is unauthenticated if the plugin is enabled. Use that only behind a private ingress you fully trust.
  • Requests dispatch through the same Gateway method handlers and scope checks as WebSocket RPC, after the plugin route auth passes.
  • Keep this route on loopback, tailnet, or a private trusted ingress. Do not expose it directly to the public internet. Use separate gateways when callers cross trust boundaries.

Request

POST /api/v1/admin/rpc
Authorization: Bearer <gateway-token>
Content-Type: application/json
{
  "id": "optional-request-id",
  "method": "health",
  "params": {}
}

Fields:

  • id (string, optional): copied into the response. A UUID is generated when omitted.
  • method (string, required): allowed Gateway method name.
  • params (any, optional): method-specific params.

The default max request body size is 1 MB.

Response

Success responses use the Gateway RPC shape:

{
  "id": "optional-request-id",
  "ok": true,
  "payload": {}
}

Gateway method errors use:

{
  "id": "optional-request-id",
  "ok": false,
  "error": {
    "code": "INVALID_REQUEST",
    "message": "bad params"
  }
}

HTTP status follows the error code:

Error code HTTP status
INVALID_REQUEST 400
APPROVAL_NOT_FOUND 404
NOT_LINKED, NOT_PAIRED 409
UNAVAILABLE 503
AGENT_TIMEOUT 504
any other code 500

Allowed methods

  • discovery: commands.list Returns the HTTP RPC method names allowed by this plugin.
  • gateway: health, status, logs.tail, usage.status, usage.cost, gateway.restart.request
  • config: config.get, config.schema, config.schema.lookup, config.set, config.patch, config.apply
  • channels: channels.status, channels.start, channels.stop, channels.logout
  • web: web.login.start, web.login.wait
  • models: models.list, models.authStatus
  • agents: agents.list, agents.create, agents.update, agents.delete
  • approvals: exec.approvals.get, exec.approvals.set, exec.approvals.node.get, exec.approvals.node.set
  • cron: cron.status, cron.list, cron.get, cron.runs, cron.add, cron.update, cron.remove, cron.run
  • devices: device.pair.list, device.pair.approve, device.pair.reject, device.pair.remove
  • nodes: node.list, node.describe, node.pair.list, node.pair.approve, node.pair.reject, node.pair.remove, node.rename
  • tasks: tasks.list, tasks.get, tasks.cancel
  • diagnostics: doctor.memory.status, update.status

Other Gateway methods are blocked until they are intentionally added.

WebSocket comparison

The normal Gateway WebSocket RPC path remains the preferred control-plane API for OpenClaw clients. Use admin HTTP RPC only for host tooling that needs a request/response HTTP surface.

Shared-token WebSocket clients without a trusted device identity cannot self-declare admin scopes during connect. Admin HTTP RPC deliberately follows the existing trusted HTTP operator model: when the plugin is enabled, shared-secret bearer auth is treated as full operator access for this admin surface.

Troubleshooting

404 Not Found

The plugin is disabled, the Gateway has not restarted since enabling it, or the request is going to a different Gateway process.

401 Unauthorized

The request did not satisfy Gateway HTTP auth. Check the bearer token or the trusted-proxy identity headers.

405 Method Not Allowed

The request used something other than POST.

413 Payload Too Large

The request body exceeded the 1 MB limit.

400 INVALID_REQUEST

The request body is not valid JSON, the method field is missing, or the method is not in the plugin allowlist.

503 UNAVAILABLE

The Gateway method handler is unavailable. Check Gateway logs and retry after the Gateway finishes startup.