Gateway — Control Plane & Authentication
The Front Door of OpenClaw
Gateway is the control plane that manages every connection entering the system — from device authentication and rate limiting to boot orchestration, message routing, session lifecycle, and assistant identity resolution. It is the single entry point through which all client traffic flows before reaching agents.
TypeScript Control Plane Auth Security-Critical
What Is This & Why Does It Exist?
Every production system needs a front door — something that decides who gets in, how services start up, and where messages go. The Gateway module is that front door for OpenClaw.
💡 Real-world analogy
Think of Gateway as an airport terminal. The Auth subsystem is passport control — it checks your credentials (token, password, Tailscale identity, or device pairing) and decides whether to let you through. Rate limiting is the queue-management system that prevents the terminal from being overwhelmed. Boot is the pre-flight checklist that ensures all ground systems are operational before any planes depart. Routing is the air-traffic controller that dispatches each passenger to the correct gate (session) and ensures the right pilot (assistant identity) is assigned to each flight.
Table of Contents
Architecture Overview
The Gateway sits between external clients (CLI, Web UI, mobile apps) and internal OpenClaw subsystems (agents, sessions, plugins). It enforces authentication, manages connection lifecycle, and routes RPC requests.
flowchart TB
subgraph Clients
CLI["CLI Client"]
WEB["Web UI"]
MOB["Mobile App"]
end
subgraph Gateway["Gateway Control Plane"]
AUTH["Auth Layer
resolveGatewayAuth()
authorizeGatewayConnect()"]
RL["Rate Limiter
AuthRateLimiter"]
BOOT["Boot Orchestrator
runBootOnce()"]
PROTO["Protocol Validation
80+ validators"]
ROUTER["Request Router
GatewayRequestHandlers"]
SESS["Session Manager
GatewaySessionRow"]
IDENT["Assistant Identity
resolveAssistantIdentity()"]
CRED["Credential Resolver
resolveGatewayCredentialsFromConfig()"]
end
subgraph Internal["Internal Services"]
AGENTS["Agent Runtime"]
PLUGINS["Plugin System"]
STORAGE["Session Storage"]
HEALTH["Health Monitor"]
end
CLI --> AUTH
WEB --> AUTH
MOB --> AUTH
AUTH --> RL
RL --> PROTO
PROTO --> ROUTER
ROUTER --> SESS
ROUTER --> IDENT
ROUTER --> AGENTS
ROUTER --> PLUGINS
SESS --> STORAGE
BOOT --> HEALTH
AUTH --> CRED
Data Flow
A typical client connection follows this sequence from initial handshake through authenticated request dispatch.
sequenceDiagram
participant C as Client
participant GW as Gateway
participant Auth as Auth Layer
participant RL as Rate Limiter
participant Proto as Protocol
participant Router as Router
participant Sess as Session Mgr
participant Agent as Agent Runtime
C->>GW: WebSocket connect (ConnectParams)
GW->>Auth: authorizeGatewayConnect(params)
Auth->>RL: rateLimiter.check(clientIp)
RL-->>Auth: RateLimitCheckResult {allowed, remaining}
Auth->>Auth: resolveGatewayAuth(cfg)
Auth-->>GW: GatewayAuthResult {ok, method, user}
GW->>Proto: validateConnectParams(frame)
Proto-->>GW: validated
GW->>GW: runBootOnce(cfg, deps)
GW->>Router: dispatch(RequestFrame)
Router->>Sess: create/resume session
Sess-->>Router: GatewaySessionRow
Router->>Agent: forward to agent runtime
Agent-->>Router: response stream
Router-->>C: ResponseFrame / EventFrame
Narrated Walkthrough
Follow the journey of a single client request through the Gateway, step by step.
Step 1 — Client Initiates Connection
A CLI, Web UI, or mobile client opens a WebSocket connection, sending ConnectParams that include the client version, requested auth method, and optional device token.
Step 2 — Credential Resolution
The Gateway calls resolveGatewayCredentialsFromConfig() to determine which credentials apply. It checks environment variables, config files, and secret references in precedence order defined by GatewayCredentialPrecedence.
Step 3 — Auth Mode Resolution
resolveGatewayAuth() examines the config to determine the active auth mode: "none", "token", "password", or "trusted-proxy". If both token and password are configured, assertExplicitGatewayAuthModeWhenBothConfigured() enforces that an explicit mode is declared.
Step 4 — Rate Limit Check
Before evaluating credentials, the AuthRateLimiter checks the client IP against a sliding-window counter. The RateLimitConfig defines maxAttempts (default 10), windowMs (60 s), and lockoutMs (5 min). If the client is locked out, the request is rejected with retryAfterMs.
Step 5 — Authentication
authorizeGatewayConnect() evaluates the request against the resolved auth mode. It supports six methods: none, token, password, tailscale, device-token, and trusted-proxy. On failure, rateLimiter.recordFailure() is called.
Step 6 — Protocol Validation
All incoming frames are validated by the protocol layer (80+ JSON-schema validators). validateRequestFrame() and validateConnectParams() ensure type safety before any processing.
Step 7 — Boot Sequence
On first connection, runBootOnce() reads BOOT.md from the workspace directory and executes the bootstrap instructions. The result is a BootRunResult with status "ran", "skipped", or "failed".
Step 8 — Request Routing
Authenticated requests are dispatched through GatewayRequestHandlers — a Record<string, GatewayRequestHandler> that maps RPC method names to handler functions. Each handler receives a GatewayRequestHandlerOptions containing the request frame, client info, and full GatewayRequestContext.
Step 9 — Session Management
The session manager creates or resumes a GatewaySessionRow (32+ fields). It tracks SessionRunStatus ("running", "done", "failed", "killed", "timeout"), token usage, cost estimates, and derived titles. Lifecycle events are persisted via persistGatewaySessionLifecycleEvent().
Step 10 — Assistant Identity
resolveAssistantIdentity() determines the active assistant’s name, avatar, and emoji from config and workspace files. The default is DEFAULT_ASSISTANT_IDENTITY (agentId: "main", name: "Assistant"). Identity fields are bounded by MAX_ASSISTANT_NAME (50), MAX_ASSISTANT_AVATAR (200), and MAX_ASSISTANT_EMOJI (16).
Key Types & Functions
| Name | File | Description |
|---|---|---|
ResolvedGatewayAuth | auth.ts | Resolved auth config: mode, token, password, allowTailscale, trustedProxy |
GatewayAuthResult | auth.ts | Auth outcome: ok, method, user, reason, rateLimited, retryAfterMs |
AuthRateLimiter | auth-rate-limit.ts | Rate limiter interface: check(), recordFailure(), reset(), prune() |
RateLimitConfig | auth-rate-limit.ts | Config: maxAttempts, windowMs, lockoutMs, exemptLoopback |
BootRunResult | boot.ts | Boot outcome: status “ran” | “skipped” | “failed” |
GatewayRequestContext | server-methods/types.ts | Full server context with 25+ fields: deps, cron, broadcast, nodeRegistry |
GatewayRequestHandler | server-methods/types.ts | Handler function type: (opts) => Promise<void> |
GatewaySessionRow | session-utils.types.ts | Session row with 32+ fields: key, kind, status, tokens, cost |
AssistantIdentity | assistant-identity.ts | Identity: agentId, name, avatar, emoji |
GatewayConnectionDetails | connection-details.ts | Connection info: url, urlSource, bindDetail, message |
ResolvedGatewayCredentials | credentials.ts | Resolved credentials: token, password |
ConnectParams | protocol/index.ts | Client connection parameters (validated by JSON schema) |
Sub-Modules
🔒 Auth
Authentication, device pairing, rate limiting, install policies, and auth-mode configuration.
resolveGatewayAuth()— mode resolutionauthorizeGatewayConnect()— connection authAuthRateLimiter— sliding-window rate limiter
🚀 Boot
Startup orchestration, capability negotiation, and health checks for gateway initialization.
runBootOnce()— one-shot bootstrapBOOT.mdexecution — workspace init- Health monitoring integration
🔌 Routing
Message dispatch, session lifecycle management, assistant identity, and RPC request handling.
GatewayRequestHandlers— RPC dispatchGatewaySessionRow— session lifecycleresolveAssistantIdentity()— identity config
Module Interactions
| Interaction | From | To | Mechanism |
|---|---|---|---|
| Client auth check | Client | Auth Layer | authorizeGatewayConnect(AuthorizeGatewayConnectParams) |
| Rate limit enforcement | Auth Layer | Rate Limiter | rateLimiter.check(ip, scope) |
| Credential resolution | Auth Layer | Credential Resolver | resolveGatewayCredentialsFromConfig() |
| Protocol validation | Gateway | Protocol | validateRequestFrame() + 80 validators |
| Boot execution | Gateway | Boot | runBootOnce(cfg, deps, workspaceDir) |
| Request dispatch | Gateway | Router | GatewayRequestHandler(opts) |
| Session create/resume | Router | Session Manager | GatewaySessionRow + lifecycle events |
| Identity resolution | Router | Identity | resolveAssistantIdentity(cfg, agentId) |
Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
auth.mode | ResolvedGatewayAuthMode | "none" | Auth mode: none, token, password, trusted-proxy |
auth.token | string | — | Static bearer token for token auth |
auth.password | string | — | Password for password auth |
auth.allowTailscale | boolean | false | Allow Tailscale identity as auth |
rateLimit.maxAttempts | number | 10 | Max failed attempts in window |
rateLimit.windowMs | number | 60000 | Sliding window duration (ms) |
rateLimit.lockoutMs | number | 300000 | Lockout duration after max attempts |
assistant.name | string | "Assistant" | Assistant display name (max 50 chars) |
assistant.avatar | string | "A" | Avatar character or URL (max 200) |
boot.filename | string | "BOOT.md" | Bootstrap instruction file |
Directory Map
Source tree — src/gateway/
src/gateway/
├── auth.ts ← Core auth: resolveGatewayAuth, authorizeGatewayConnect
├── auth-rate-limit.ts ← AuthRateLimiter, RateLimitConfig, createAuthRateLimiter
├── auth-mode-policy.ts ← Auth mode validation, ambiguity detection
├── auth-install-policy.ts ← Install-time auth requirements
├── auth-config-utils.ts ← withGatewayAuthPassword, resolveGatewayPasswordSecretRef
├── boot.ts ← runBootOnce, BootRunResult, BOOT_FILENAME
├── assistant-identity.ts ← AssistantIdentity, resolveAssistantIdentity
├── credentials.ts ← GatewayCredentials, GatewaySecretRefUnavailableError
├── connection-auth.ts ← resolveGatewayConnectionAuth
├── connection-details.ts ← GatewayConnectionDetails
├── call.ts ← buildGatewayConnectionDetails
├── session-utils.types.ts ← GatewaySessionRow (32+ fields), SessionRunStatus
├── session-lifecycle-state.ts ← Lifecycle snapshots, persistGatewaySessionLifecycleEvent
├── protocol/
│ └── index.ts ← 80+ JSON schema validators, ConnectParams, RequestFrame
├── server/
│ └── ws-types.ts ← GatewayWsClient, WebSocket client type
└── server-methods/
└── types.ts ← GatewayRequestContext, GatewayRequestHandler