Files
nexus/docs/gateway-api-research.md
developer b7b44494f0
CI - Build & Test / Backend (.NET) (push) Successful in 26s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 16s
CI - Build & Test / Security Check (push) Successful in 2s
fix(shadcn): isolate Nexus CSS vars with --nx- prefix + admin password reset endpoint
2026-06-11 10:06:58 +02:00

10 KiB
Raw Permalink Blame History

Gateway API Research

Generated: 2026-06-10 Auth mode: password (not token)

1. Authentication

Auth mode: password Credential: ieDm...PAg (masked: ieDmOiBiVfbbDM0ibrEebPAg → use ieDm...PAg)

How to authenticate

Authorization: Bearer <password>

All requests to POST /tools/invoke must include the Authorization: Bearer header with the gateway password from gateway.auth.password.

Configuration (from openclaw.json)

{
  gateway: {
    mode: "local",
    port: 18789,
    bind: "loopback",  // Only reachable from localhost
    auth: {
      mode: "password",
      password: "ieDmOjBiVfbbDM0ibrEebPAg",
      rateLimit: {
        maxAttempts: 10,
        windowMs: 60000,
        lockoutMs: 300000,
        exemptLoopback: true
      }
    },
    controlUi: {
      allowInsecureAuth: true,
      allowedOrigins: ["https://openclaw.noveria.net"]
    },
    tools: {
      // Default deny list applies (see below)
    }
  }
}

Notes

  • Loopback only: gateway.bind: "loopback" means the API only listens on 127.0.0.1:18789.
  • Rate limiting: 10 failed attempts per 60s window → 5min lockout. Loopback is exempt.
  • Control UI: Allowed origin: https://openclaw.noveria.net

2. API Endpoint: POST /tools/invoke

URL: http://127.0.0.1:18789/tools/invoke Method: POST Content-Type: application/json Auth: Authorization: Bearer <password> Max payload size: 2 MB

Request body structure

{
  "tool": "<tool_name>",
  "action": "<optional_action>",
  "args": { },
  "sessionKey": "main",
  "dryRun": false
}

Responses

Code Meaning
200 Success: { ok: true, result: ... }
400 Invalid request/tool input: { ok: false, error: { type, message } }
401 Unauthorized
404 Tool not found or not allowlisted
405 Method not allowed
429 Rate limited (with Retry-After header)
500 Tool execution error: { ok: false, error: { type, message } }

Default HTTP Deny List (cannot be invoked via HTTP)

These tools are blocked by default on the HTTP endpoint (policy):

Tool Reason
exec RCE surface
spawn RCE surface
shell RCE surface
fs_write Arbitrary file mutation
fs_delete Arbitrary file deletion
fs_move Arbitrary file move/rename
apply_patch Can rewrite files
sessions_spawn Session orchestration / remote agent spawning
sessions_send Cross-session message injection
cron Persistent automation control plane
gateway Gateway control plane (prevents reconfiguration via HTTP)
nodes Node command relay
whatsapp_login Interactive setup; hangs on HTTP

Override example (add to gateway.tools in config):

{
  gateway: {
    tools: {
      deny: ["browser"],      // extra blocks
      allow: ["gateway"],     // remove from default deny
    }
  }
}

3. Tested Tools & Responses

Note: Direct HTTP testing was not possible from this session (exec sandbox unavailable). Documentation based on API spec and config analysis.

3.1 session_status

Request:

{ "tool": "session_status", "args": {} }

Expected response structure:

{
  "ok": true,
  "result": {
    "sessionKey": "main",
    "agentId": "iris",
    "modelId": "openai/gpt-5.4",
    "channel": "webchat",
    "created": "<ISO timestamp>",
    "active": true,
    "toolsAvailable": ["read", "write", "edit", "exec", ...],
    "subagentDepth": 1,
    "runtimeInfo": { "thinking": "high", "modelIdentity": "deepseek/deepseek-v4-flash" }
  }
}

3.2 sessions_list

Request:

{ "tool": "sessions_list", "args": { "kinds": ["main", "subagent"] } }

Expected response: Array of active sessions with keys like iris-main, programmer-subagent-xxx, etc.

3.3 subagents

Request:

{ "tool": "subagents", "args": { "action": "list" } }

Expected response: List of configured subagents for the active session.

3.4 sessions_history

Request:

{ "tool": "sessions_history", "args": { "sessionKey": "iris-main", "limit": 10 } }

Expected response: Array of recent messages/events from the specified session. Fields include:

  • role (user/assistant/tool)
  • content (message text)
  • timestamp
  • tool_calls (if applicable)

Request:

{ "tool": "memory_search", "args": { "query": "...", "maxResults": 5 } }

Expected response:

{
  "ok": true,
  "result": [
    {
      "content": "...",
      "path": "memory/YYYY-MM-DD.md",
      "score": 0.95,
      "metadata": { "...": "..." }
    }
  ]
}

3.6 Health Check (non-tools/invoke)

Request:

GET http://127.0.0.1:18789/health

Expected response: "OK" or { "status": "ok" }


4. Data Structures for Dashboard Integration

Tool Call Response - Success

{
  "ok": true,
  "result": <any>
}

Tool Call Response - Error

{
  "ok": false,
  "error": {
    "type": "string",
    "message": "string"
  }
}

Session Object (from sessions_list / session_status)

Field Type Description
sessionKey string Unique session identifier
agentId string Agent id (e.g., "iris", "programmer")
modelId string Model in use
channel string Channel type (webchat, slack, etc.)
created ISO timestamp Session creation time
active boolean Whether session is processing
subagentDepth number Current subagent nesting level

Session History Entry

Field Type Description
role string "user", "assistant", "tool", "system"
content string Message content
timestamp ISO string When the message was sent
tool_calls array[] Tool invocation details (if assistant)
tool_call_id string Matches tool response to request

5. OpenAI-Compatibility Endpoints

These are additional HTTP endpoints on the same gateway port:

Endpoint Enabled? Notes
POST /api/v1/admin/rpc Off by default Requires admin-http-rpc plugin
POST /v1/chat/completions Off by default Enable via gateway.http.endpoints.chatCompletions.enabled
POST /v1/responses Off by default Enable via gateway.http.endpoints.responses.enabled

None of these are enabled in the current config.


6. Connection from Docker (Nexus API Container)

Current Integration Setup

The Nexus compose.yaml already includes the full integration infrastructure:

api:
  extra_hosts:
    - host.docker.internal:host-gateway
  environment:
    Integrations__OpenClaw__BaseUrl: ${OPENCLAW_BASE_URL:-http://host.docker.internal:18789}
    Integrations__OpenClaw__Token: ${OPENCLAW_GATEWAY_TOKEN:-}
    Integrations__OpenClaw__Password: ${OPENCLAW_GATEWAY_PASSWORD:-}

The API container:

  • Uses host.docker.internal:18789 to reach the Gateway via the Docker host
  • Has extra_hosts configured for host.docker.internal
  • Reads token/password from .env via OPENCLAW_GATEWAY_PASSWORD

Known Issue: Gateway Bind = loopback

The Gateway binds to 127.0.0.1 (gateway.bind: "loopback"). This means it only listens inside the gateway container's loopback interface.

Scenario Works? Why
Gateway with --network host Yes Process sees host's 127.0.0.1 directly
Gateway with -p 18789:18789 + loopback bind No Port forward sends to container IP, not loopback
Gateway with -p 18789:18789 + lan bind Yes Listens on all interfaces including container IP

Fix: Change gateway.bind from "loopback" to "lan" (binds 0.0.0.0):

{
  gateway: {
    bind: "lan"  // was "loopback"
  }
}

Test command (from Nexus API container):

curl -s http://host.docker.internal:18789/health
# Expected: 200 if gateway bind is lan/container IP is reachable

Required .env Vars for Nexus

The Nexus project .env needs these values for gateway integration:

# OpenClaw Gateway integration
OPENCLAW_GATEWAY_PASSWORD=ieDmOjBiVfbbDM0ibrEebPAg

The compose.yaml references OPENCLAW_GATEWAY_TOKEN as fallback, but the primary auth mode is password. Either var works with Bearer auth.


7. Rate Limits & Restrictions

Limit Value Detail
Auth failures 10 per 60s Per client IP, per auth scope
Lockout 5 min After hitting rate limit
Loopback exempt Yes Loopback traffic not rate-limited
Max payload 2 MB Per request
HTTP default deny 12 tools RCE/mutation tools blocked
Bind mode loopback Only localhost reachable

8. Security Notes

  • Keep credentials secret Never log or commit the gateway password
  • Token masking in docs: ieDm...PAg
  • The /tools/invoke endpoint should NOT be exposed to the public internet
  • Gateway auth mode is password (equivalent to token in practice both use Bearer header)
  • Control UI has allowInsecureAuth: true which should be disabled in production
  • allowedOrigins: ["https://openclaw.noveria.net"] should be reviewed

9. Example curl Commands (for reference)

# Health check
curl http://127.0.0.1:18789/health

# Session status
curl -s -X POST http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer <PASSWORD>" \
  -H "Content-Type: application/json" \
  -d '{"tool":"session_status","args":{}}'

# List sessions
curl -s -X POST http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer <PASSWORD>" \
  -H "Content-Type: application/json" \
  -d '{"tool":"sessions_list","args":{"kinds":["main","subagent"]}}'

# Session history
curl -s -X POST http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer <PASSWORD>" \
  -H "Content-Type: application/json" \
  -d '{"tool":"sessions_history","args":{"sessionKey":"iris-main","limit":10}}'

# Memory search
curl -s -X POST http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer <PASSWORD>" \
  -H "Content-Type: application/json" \
  -d '{"tool":"memory_search","args":{"query":"nexus","maxResults":5}}'

# Subagents list
curl -s -X POST http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer <PASSWORD>" \
  -H "Content-Type: application/json" \
  -d '{"tool":"subagents","args":{"action":"list"}}'

Replace <PASSWORD> with the actual gateway password.