docs/channels/pairing.md
“Pairing” is OpenClaw’s explicit access approval step. It is used in two places:
Security context: Security
When a channel is configured with DM policy pairing, unknown senders get a short code and their message is not processed until you approve.
Default DM policies are documented in: Security
dmPolicy: "open" is public only when the effective DM allowlist includes "*".
Setup and validation require that wildcard for public-open configs. If existing
state contains open with concrete allowFrom entries, runtime still admits
only those senders, and pairing-store approvals do not widen open access.
Pairing codes:
0O1I).openclaw pairing list telegram
openclaw pairing approve telegram <CODE>
If no command owner is configured yet, approving a DM pairing code also bootstraps
commands.ownerAllowFrom to the approved sender, such as telegram:123456789.
That gives first-time setups an explicit owner for privileged commands and exec
approval prompts. After an owner exists, later pairing approvals only grant DM
access; they do not add more owners.
Supported channels: bluebubbles, discord, feishu, googlechat, imessage, irc, line, matrix, mattermost, msteams, nextcloud-talk, nostr, openclaw-weixin, signal, slack, synology-chat, telegram, twitch, whatsapp, zalo, zalouser.
Use top-level accessGroups when the same trusted sender set should apply to
multiple message channels or to both DM and group allowlists.
Static groups use type: "message.senders" and are referenced with
accessGroup:<name> from channel allowlists:
{
accessGroups: {
operators: {
type: "message.senders",
members: {
discord: ["discord:123456789012345678"],
telegram: ["987654321"],
whatsapp: ["+15551234567"],
},
},
},
channels: {
telegram: { dmPolicy: "allowlist", allowFrom: ["accessGroup:operators"] },
whatsapp: { groupPolicy: "allowlist", groupAllowFrom: ["accessGroup:operators"] },
},
}
Access groups are documented in detail here: Access groups
Stored under ~/.openclaw/credentials/:
<channel>-pairing.json<channel>-allowFrom.json<channel>-<accountId>-allowFrom.jsonAccount scoping behavior:
Treat these as sensitive (they gate access to your assistant).
<Note> The pairing allowlist store is for DM access. Group authorization is separate. Approving a DM pairing code does not automatically allow that sender to run group commands or control the bot in groups. First-owner bootstrap is separate config state in `commands.ownerAllowFrom`, and group chat delivery still follows the channel's group allowlists (for example `groupAllowFrom`, `groups`, or per-group or per-topic overrides depending on the channel). </Note>Nodes connect to the Gateway as devices with role: node. The Gateway
creates a device pairing request that must be approved.
If you use the device-pair plugin, you can do first-time device pairing entirely from Telegram:
/pair/pair pending (review request IDs, role, and scopes), then approve.The setup code is a base64-encoded JSON payload that contains:
url: the Gateway WebSocket URL (ws://... or wss://...)bootstrapToken: a short-lived single-device bootstrap token used for the initial pairing handshakeThat bootstrap token carries the built-in pairing bootstrap profile:
node token stays scopes: []operator token stays bounded to the bootstrap allowlist:
operator.approvals, operator.read, operator.talk.secrets, operator.writeTreat the setup code like a password while it is valid.
For Tailscale, public, or other non-loopback mobile pairing, use Tailscale
Serve/Funnel or another wss:// Gateway URL. Direct non-loopback ws:// setup
URLs are rejected before QR/setup-code issuance. Plaintext ws:// setup codes
are limited to loopback URLs; private-network ws:// clients still require the explicit
OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 break-glass described in the remote
Gateway guide.
openclaw devices list
openclaw devices approve <requestId>
openclaw devices reject <requestId>
When an explicit approval is denied because the approving paired-device session
was opened with pairing-only scope, the CLI retries the same request with
operator.admin. This lets an existing admin-capable paired device recover a new
Control UI/browser pairing without editing devices/paired.json by hand. The
Gateway still validates the retried connection; tokens that cannot authenticate
with operator.admin remain blocked.
If the same device retries with different auth details (for example different
role/scopes/public key), the previous pending request is superseded and a new
requestId is created.
Device pairing remains manual by default. For tightly controlled node networks, you can opt in to first-time node auto-approval with explicit CIDRs or exact IPs:
{
gateway: {
nodes: {
pairing: {
autoApproveCidrs: ["192.168.1.0/24"],
},
},
},
}
This only applies to fresh role: node pairing requests with no requested
scopes. Operator, browser, Control UI, and WebChat clients still require manual
approval. Role, scope, metadata, and public-key changes still require manual
approval.
Stored under ~/.openclaw/devices/:
pending.json (short-lived; pending requests expire)paired.json (paired devices + tokens)node.pair.* API (CLI: openclaw nodes pending|approve|reject|remove|rename) is a
separate gateway-owned pairing store. WS nodes still require device pairing.