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.

441
Source Files
4
Auth Modes
80+
Protocol Validators
32+
Session Fields

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

NameFileDescription
ResolvedGatewayAuthauth.tsResolved auth config: mode, token, password, allowTailscale, trustedProxy
GatewayAuthResultauth.tsAuth outcome: ok, method, user, reason, rateLimited, retryAfterMs
AuthRateLimiterauth-rate-limit.tsRate limiter interface: check(), recordFailure(), reset(), prune()
RateLimitConfigauth-rate-limit.tsConfig: maxAttempts, windowMs, lockoutMs, exemptLoopback
BootRunResultboot.tsBoot outcome: status “ran” | “skipped” | “failed”
GatewayRequestContextserver-methods/types.tsFull server context with 25+ fields: deps, cron, broadcast, nodeRegistry
GatewayRequestHandlerserver-methods/types.tsHandler function type: (opts) => Promise<void>
GatewaySessionRowsession-utils.types.tsSession row with 32+ fields: key, kind, status, tokens, cost
AssistantIdentityassistant-identity.tsIdentity: agentId, name, avatar, emoji
GatewayConnectionDetailsconnection-details.tsConnection info: url, urlSource, bindDetail, message
ResolvedGatewayCredentialscredentials.tsResolved credentials: token, password
ConnectParamsprotocol/index.tsClient connection parameters (validated by JSON schema)

Sub-Modules

🔒 Auth

Authentication, device pairing, rate limiting, install policies, and auth-mode configuration.

  • resolveGatewayAuth() — mode resolution
  • authorizeGatewayConnect() — connection auth
  • AuthRateLimiter — sliding-window rate limiter

🚀 Boot

Startup orchestration, capability negotiation, and health checks for gateway initialization.

  • runBootOnce() — one-shot bootstrap
  • BOOT.md execution — workspace init
  • Health monitoring integration

🔌 Routing

Message dispatch, session lifecycle management, assistant identity, and RPC request handling.

  • GatewayRequestHandlers — RPC dispatch
  • GatewaySessionRow — session lifecycle
  • resolveAssistantIdentity() — identity config

Module Interactions

InteractionFromToMechanism
Client auth checkClientAuth LayerauthorizeGatewayConnect(AuthorizeGatewayConnectParams)
Rate limit enforcementAuth LayerRate LimiterrateLimiter.check(ip, scope)
Credential resolutionAuth LayerCredential ResolverresolveGatewayCredentialsFromConfig()
Protocol validationGatewayProtocolvalidateRequestFrame() + 80 validators
Boot executionGatewayBootrunBootOnce(cfg, deps, workspaceDir)
Request dispatchGatewayRouterGatewayRequestHandler(opts)
Session create/resumeRouterSession ManagerGatewaySessionRow + lifecycle events
Identity resolutionRouterIdentityresolveAssistantIdentity(cfg, agentId)

Configuration

ParameterTypeDefaultDescription
auth.modeResolvedGatewayAuthMode"none"Auth mode: none, token, password, trusted-proxy
auth.tokenstring—Static bearer token for token auth
auth.passwordstring—Password for password auth
auth.allowTailscalebooleanfalseAllow Tailscale identity as auth
rateLimit.maxAttemptsnumber10Max failed attempts in window
rateLimit.windowMsnumber60000Sliding window duration (ms)
rateLimit.lockoutMsnumber300000Lockout duration after max attempts
assistant.namestring"Assistant"Assistant display name (max 50 chars)
assistant.avatarstring"A"Avatar character or URL (max 200)
boot.filenamestring"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