OpenClaw Gatewayプロトコル接続ガイド:WebSocket実装手順
分散システムにおいて、多数のクライアントやノードをリアルタイムで同期させ、かつセキュアに管理するのは非常に骨が折れる作業です。通信の遅延や認証の複雑さに悩まされた経験がある開発者も多いのではないでしょうか。
OpenClaw では、こうした課題を解決するために WebSocket をベースにした Gateway プロトコルを採用しています。このプロトコルは、OpenClaw の単一のコントロールプレーンおよびノード間のトランスポートとして機能します。CLI、Web UI、モバイルアプリ、各種ノードなど、すべてのクライアントは WebSocket を通じて接続し、ハンドシェイク時に自身の role(ロール)と scope(スコープ)を宣言する仕組みになっています。
トランスポート
Section titled “トランスポート”- WebSocket を使用し、JSON ペイロードを含むテキストフレームで通信します。
- 接続後の最初のフレームは、必ず
connectリクエストである必要があります。
ハンドシェイク (connect)
Section titled “ハンドシェイク (connect)”Gateway → Client (接続前のチャレンジ):
{ "type": "event", "event": "connect.challenge", "payload": { "nonce": "…", "ts": 1737264000000 }}Client → Gateway:
{ "type": "req", "id": "…", "method": "connect", "params": { "minProtocol": 3, "maxProtocol": 3, "client": { "id": "cli", "version": "1.2.3", "platform": "macos", "mode": "operator" }, "role": "operator", "scopes": ["operator.read", "operator.write"], "caps": [], "commands": [], "permissions": {}, "auth": { "token": "…" }, "locale": "en-US", "userAgent": "openclaw-cli/1.2.3", "device": { "id": "device_fingerprint", "publicKey": "…", "signature": "…", "signedAt": 1737264000000, "nonce": "…" } }}Gateway → Client:
{ "type": "res", "id": "…", "ok": true, "payload": { "type": "hello-ok", "protocol": 3, "policy": { "tickIntervalMs": 15000 } }}デバイス用のトークンが発行される場合、hello-ok には以下も含まれます。
{ "auth": { "deviceToken": "…", "role": "operator", "scopes": ["operator.read", "operator.write"] }}Node の例
Section titled “Node の例”{ "type": "req", "id": "…", "method": "connect", "params": { "minProtocol": 3, "maxProtocol": 3, "client": { "id": "ios-node", "version": "1.2.3", "platform": "ios", "mode": "node" }, "role": "node", "scopes": [], "caps": ["camera", "canvas", "screen", "location", "voice"], "commands": ["camera.snap", "canvas.navigate", "screen.record", "location.get"], "permissions": { "camera.capture": true, "screen.record": false }, "auth": { "token": "…" }, "locale": "en-US", "userAgent": "openclaw-ios/1.2.3", "device": { "id": "device_fingerprint", "publicKey": "…", "signature": "…", "signedAt": 1737264000000, "nonce": "…" } }}フレーミング
Section titled “フレーミング”- Request:
{type:"req", id, method, params} - Response:
{type:"res", id, ok, payload|error} - Event:
{type:"event", event, payload, seq?, stateVersion?}
副作用を伴うメソッドには、idempotency keys(べき等キー)が必要です(詳細はスキーマを参照してください)。
ロールとスコープ
Section titled “ロールとスコープ”operator: コントロールプレーンのクライアント(CLI、UI、自動化ツールなど)。node: 機能をホストする側(カメラ、スクリーン、キャンバス、system.run など)。
スコープ (operator)
Section titled “スコープ (operator)”よく使われるスコープは以下の通りです。
operator.readoperator.writeoperator.adminoperator.approvalsoperator.pairing
メソッドのスコープは最初のチェックゲートに過ぎません。chat.send 経由で実行される一部のスラッシュコマンドには、さらに厳格なコマンドレベルのチェックが適用されます。例えば、永続的な /config set や /config unset の書き込みには operator.admin が必要です。
Caps / commands / permissions (node)
Section titled “Caps / commands / permissions (node)”Node は接続時に自身の機能(capability)を宣言します。
caps: 高レベルな機能カテゴリ。commands: 実行を許可するコマンドのホワイトリスト。permissions: 詳細な切り替え設定(例:screen.record,camera.capture)。
Gateway はこれらを「自己申告(claims)」として扱い、サーバー側のホワイトリストに基づいて制限を適用します。
system-presenceは、デバイスの識別子をキーとしたエントリを返します。- プレゼンスエントリには
deviceId、roles、scopesが含まれます。これにより、あるデバイスが operator と node の両方として接続している場合でも、UI 上では 1 つのデバイスとして表示できます。
Node 用のヘルパーメソッド
Section titled “Node 用のヘルパーメソッド”- Node は
skills.binsを呼び出して、自動許可チェック用のスキル実行ファイルリストを取得できます。
Operator 用のヘルパーメソッド
Section titled “Operator 用のヘルパーメソッド”- Operator は
tools.catalog(operator.read) を呼び出して、エージェントのランタイムツールカタログを取得できます。レスポンスにはグループ化されたツールとメタデータが含まれます。source:coreまたはpluginpluginId:source="plugin"の場合のプラグイン所有者optional: プラグインツールがオプションかどうか
- Operator は
tools.effective(operator.read) を呼び出して、セッションで有効なツールのインベントリを取得できます。sessionKeyが必須です。- Gateway は、呼び出し元から提供された認証情報ではなく、サーバー側のセッションから信頼できる実行コンテキストを導き出します。
- レスポンスはセッションスコープであり、コアツール、プラグイン、チャネルツールを含め、現在のアクティブな会話で使用可能なものが反映されます。
実行の承認 (Exec approvals)
Section titled “実行の承認 (Exec approvals)”- 実行リクエストに承認が必要な場合、Gateway は
exec.approval.requestedをブロードキャストします。 - Operator クライアントは
exec.approval.resolveを呼び出してこれを解決します(operator.approvalsスコアが必要です)。 host=nodeの場合、exec.approval.requestにはsystemRunPlan(標準的なargv,cwd,rawCommand, セッションメタデータ)を含める必要があります。systemRunPlanがないリクエストは拒否されます。
エージェント配信のフォールバック
Section titled “エージェント配信のフォールバック”agentリクエストにdeliver=trueを含めることで、外部への配信をリクエストできます。bestEffortDeliver=falseの場合、厳格な挙動となります。解決できない配信先や内部専用の配信先を指定するとINVALID_REQUESTが返されます。bestEffortDeliver=trueの場合、外部への配信ルートが解決できないとき(内部セッションや Web チャット、曖昧なマルチチャネル設定など)に、セッション内での実行にフォールバックすることを許可します。
バージョニング
Section titled “バージョニング”PROTOCOL_VERSIONはsrc/gateway/protocol/schema.tsで定義されています。- クライアントは
minProtocolとmaxProtocolを送信し、サーバー側で不一致がある場合は接続を拒否します。 - スキーマとモデルは TypeBox の定義から生成されます。
pnpm protocol:genpnpm protocol:gen:swiftpnpm protocol:check
認証 (Auth)
Section titled “認証 (Auth)”OPENCLAW_GATEWAY_TOKEN(または--token)が設定されている場合、connect.params.auth.tokenが一致しないとソケットは閉じられます。- ペアリング後、Gateway は接続ロールとスコープに応じた device token を発行します。これは
hello-ok.auth.deviceTokenで返され、クライアントは次回の接続のためにこれを保存しておく必要があります。 - デバイストークンは
device.token.rotateやdevice.token.revokeで更新・失効させることができます(operator.pairingスコアが必要です)。 - 認証エラーには
error.details.codeとリカバリのためのヒントが含まれます。error.details.canRetryWithDeviceToken(boolean)error.details.recommendedNextStep(retry_with_device_token,update_auth_configuration,update_auth_credentials,wait_then_retry,review_auth_configuration)
AUTH_TOKEN_MISMATCH時のクライアントの挙動:- 信頼されたクライアントは、キャッシュされたデバイストークンを使用して 1 回だけ再試行を試みることができます。
- 再試行に失敗した場合は、自動再接続ループを停止し、ユーザーに適切なアクションを促す必要があります。
デバイス ID とペアリング
Section titled “デバイス ID とペアリング”- Node は、キーペアのフィンガープリントから派生した固定のデバイス ID (
device.id) を含める必要があります。 - Gateway はデバイスとロールの組み合わせごとにトークンを発行します。
- 新しいデバイス ID の場合、ローカルの自動承認が有効でない限り、ペアリングの承認が必要です。
- ローカル接続には、ループバックアドレスおよび Gateway ホスト自身の Tailscale アドレスが含まれます(同一ホストの Tailscale 経由であれば自動承認が可能です)。
- すべての WebSocket クライアントは、
connect時にdeviceID を含める必要があります。コントロール UI でこれを省略できるのは、以下のモードに限られます。gateway.controlUi.allowInsecureAuth=true: localhost 限定の非セキュアな HTTP 互換用。gateway.controlUi.dangerouslyDisableDeviceAuth=true: 緊急用(セキュリティレベルが著しく低下します)。
- すべての接続において、サーバーから提供された
connect.challengeの nonce に対して署名を行う必要があります。
デバイス認証移行用の診断
Section titled “デバイス認証移行用の診断”チャレンジ前の署名方式を使用している古いクライアントのために、connect は error.details.code に DEVICE_AUTH_* コードを返し、error.details.reason に詳細な理由を含めます。
よくある移行時のエラー:
| メッセージ | details.code | details.reason | 意味 |
|---|---|---|---|
device nonce required | DEVICE_AUTH_NONCE_REQUIRED | device-nonce-missing | クライアントが device.nonce を省略した(または空で送った)。 |
device nonce mismatch | DEVICE_AUTH_NONCE_MISMATCH | device-nonce-mismatch | クライアントが古い、または間違った nonce で署名した。 |
device signature invalid | DEVICE_AUTH_SIGNATURE_INVALID | device-signature | 署名のペイロードが v2 の形式と一致しない。 |
device signature expired | DEVICE_AUTH_SIGNATURE_EXPIRED | device-signature-stale | 署名されたタイムスタンプが許容範囲外。 |
device identity mismatch | DEVICE_AUTH_DEVICE_ID_MISMATCH | device-id-mismatch | device.id が公開鍵のフィンガープリントと一致しない。 |
device public key invalid | DEVICE_AUTH_PUBLIC_KEY_INVALID | device-public-key | 公開鍵のフォーマットまたは正規化に失敗した。 |
移行のポイント:
- 常に
connect.challengeを待機してください。 - サーバーの nonce を含む v2 ペイロードに署名してください。
connect.params.device.nonceに同じ nonce を含めて送信してください。- 推奨される署名ペイロードは
v3です。これはデバイス、クライアント、ロール、スコープ、トークン、nonce に加え、platformとdeviceFamilyも紐付けます。 - 互換性のためにレガシーな
v2署名も受け入れられますが、再接続時のコマンドポリシーはペアリングされたデバイスのメタデータによって制御されます。
TLS とピン留め (Pinning)
Section titled “TLS とピン留め (Pinning)”- WebSocket 接続での TLS をサポートしています。
- クライアントは、オプションで Gateway 証明書のフィンガープリントをピン留め(Pinning)できます(
gateway.tls設定、またはgateway.remote.tlsFingerprint/ CLI の--tls-fingerprintを参照してください)。
このプロトコルは、Gateway API の全機能(ステータス、チャネル、モデル、チャット、エージェント、セッション、ノード、承認など)を公開します。具体的なインターフェースは src/gateway/protocol/schema.ts 内の TypeBox スキーマで定義されています。
次のステップ
Section titled “次のステップ”OpenClaw Expert
まだ解決しませんか?
このページで解決しない場合は、OpenClaw Expertに直接質問してください。