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>
Add --notify to the approve command to tell the requester on the same channel. Multi-account channels take --account <id>.
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 (any installed channel plugin that declares pairing; external plugins such as openclaw-weixin can add more): discord, feishu, googlechat, imessage, irc, line, matrix, mattermost, msteams, nextcloud-talk, nostr, signal, slack, sms, 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>-<accountId>-allowFrom.json (approvals for the
default account use <channel>-default-allowFrom.json)Account scoping behavior:
<channel>-allowFrom.json
file from older installs; entries from both files are merged on read.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.
Use an already connected Control UI session with operator.admin access:
Official OpenClaw iOS and Android apps are approved automatically when their setup-code metadata matches. If Devices shows a pending request (for example, for a non-official client or mismatched metadata), review its role and scopes before approving it.
The button is disabled when the current Control UI session does not have administrator access. Use the CLI approval flow below from the Gateway host in that case.
If you use the device-pair plugin, you can do first-time device pairing entirely from Telegram:
/pair/pair qr) or paste the setup code and connect./pair pending shows a
request, review its role and scopes before approving it.The setup code is a base64-encoded JSON payload that contains:
url: the Gateway WebSocket URL (ws://... or wss://...)urls: when available, the ordered LAN/Tailnet routes the mobile app can trybootstrapToken: a single-use bootstrap token for the initial pairing handshake (expires after 10 minutes; expiresAtMs is included in the payload)Run /pair cleanup to invalidate unused setup codes once pairing finishes.
That bootstrap token carries the built-in pairing bootstrap profile:
node plus a bounded operator handoffnode token stays scopes: []operator token is limited to operator.approvals,
operator.read, operator.talk.secrets, and operator.writeoperator.admin is not granted by QR/setup-code bootstrap; it requires a
separate approved operator pairing or token flowTreat the setup code like a password while it is valid.
For Tailscale, public, or other remote mobile pairing, use Tailscale Serve/Funnel
or another wss:// Gateway URL. Plaintext ws:// setup codes are accepted only
for loopback, private LAN addresses, .local Bonjour hosts, and the Android
emulator host. Tailnet CGNAT addresses, .ts.net names, and public hosts still
fail closed before QR/setup-code issuance.
For gateway.bind=lan setup URLs, OpenClaw detects persistent Tailscale Serve
HTTPS roots that proxy the active Gateway's loopback port and advertises them
alongside the LAN route. Specific-interface custom and tailnet binds do not
receive that fallback because a loopback Serve proxy cannot reach those
listeners. The iOS app probes the advertised routes in order and saves the first
reachable endpoint.
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 after 5 minutes)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.