Pairing: Approving DM Access and Node Joins in OpenClaw
This page explains OpenClaw's pairing mechanism for granting DM message approval and node gateway access. It covers pairing codes, expiration, and limits for administrators.
Read this when
- Setting up DM access control
- Pairing a new iOS/Android node
- Reviewing OpenClaw security posture
"Pairing" is OpenClaw's explicit step for granting access approval.
It appears in two contexts:
- DM pairing (who can message the bot)
- Node pairing (which devices or nodes can join the gateway network)
Security context: Security
1) DM pairing (inbound chat access)
When a channel uses DM policy pairing, unknown senders receive a short code and their message is not processed until you approve.
Default DM policies are described in: Security
dmPolicy: "open" is public only when the effective DM allowlist includes "*".
Setup and validation require that wildcard for public-open configurations. If existing state contains open with concrete allowFrom entries, the runtime still admits only those senders, and pairing-store approvals do not widen open access.
Pairing codes:
- 8 characters, uppercase, no ambiguous characters (
0O1I). - Expire after 1 hour. The bot sends the pairing message only when a new request is created (roughly once per hour per sender).
- Pending DM pairing requests are capped at 3 per channel account; additional requests are ignored until one expires or is approved.
Approve from the Control UI
Open Settings → Channels → DM access requests. The queue shows pending requests from every configured channel account whose DM policy is pairing. Filter by channel or account, review the sender ID and metadata, then choose Approve.
Approval grants direct-message access only. It does not grant group access. The approval dialog also provides these explicit options when supported:
- Notify the requester after approval
- Also make this sender the first command owner, shown only when no command owner exists and the Control UI session has
operator.admin
Choose Dismiss to remove a pending request without approving it. Dismissal is not a permanent block; the sender can request access again later.
Approve from the CLI
openclaw pairing list telegram
openclaw pairing approve telegram <CODE>
Add --notify to notify the requester on the same channel. Multi-account channels use --account <id>.
Unlike the Control UI's explicit checkbox, the CLI automatically bootstraps commands.ownerAllowFrom when no command owner is configured, using an entry such as telegram:123456789. This gives first-time setups an explicit owner for privileged commands and exec approval prompts. After an owner exists, later pairing approvals grant only DM access; they do not add more owners.
Note
WhatsApp's login QR links a WhatsApp account to OpenClaw. DM access requests approve people who message that account. These are separate flows.
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.
Reusable sender groups
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
Where the state lives
Stored in the shared SQLite state database at ~/.openclaw/state/openclaw.sqlite:
- pending requests in
channel_pairing_requests - approved senders in
channel_pairing_allow_entries
Account scoping behavior:
- each request and approved sender is keyed by channel and account
- runtime reads only the canonical SQLite rows; it does not merge legacy files
Older gateways wrote <channel>-pairing.json and <channel>-<accountId>-allowFrom.json under ~/.openclaw/credentials/. Startup migration and openclaw doctor --fix import those files into SQLite and remove each source after a successful import. Treat the SQLite database as sensitive because these rows 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 examplegroupAllowFrom,groups, or per-group or per-topic overrides depending on the channel).
2) Node device pairing (iOS/Android/macOS/headless nodes)
Nodes connect to the Gateway as devices with role: node. The Gateway creates a device pairing request that must be approved.
Pair from the Control UI (recommended)
Use an already connected Control UI session with operator.admin access:
- Open the Control UI and go to Settings → Devices.
- On the Devices page, click Pair mobile device.
- Keep Full access (recommended), or select Limited access to omit administrative Gateway controls.
- Click Create setup code.
- On your phone, open the OpenClaw app → Settings → Gateway.
- Scan the QR code or paste the setup code, then connect.
Official OpenClaw iOS and Android apps are approved automatically when their setup-code metadata matches. If Pending approval shows a 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.
Pair via Telegram
If you use the device-pair plugin, you can do first-time device pairing entirely from Telegram:
- In Telegram, message your bot:
/pair - The bot replies with two messages: an instruction message and a separate setup code message (easy to copy/paste in Telegram).
- On your phone, open the OpenClaw iOS app → Settings → Gateway.
- Scan the QR code (
/pair qr) or paste the setup code and connect. - The official mobile app connects automatically. If
/pair pendingshows 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://...orwss://...)urls: when available, the ordered LAN/Tailnet routes the mobile app can trybootstrapToken: a single-use bootstrap token for the initial pairing handshake; the Gateway expires it after 10 minutes
Run /pair cleanup to invalidate unused setup codes once pairing finishes.
That bootstrap token carries the built-in pairing bootstrap profile:
- a secure
wss://setup (or same-host loopback) defaults tonodeplus full native-mobileoperatoraccess - the handed-off
nodetoken staysscopes: [] - the default handed-off
operatortoken includesoperator.admin,operator.approvals,operator.read,operator.talk.secrets, andoperator.write - Control UI Limited access and
openclaw qr --limitedomitoperator.adminwhile keeping the other operator scopes - plaintext LAN
ws://setup automatically uses the same limited profile; configurewss://or Tailscale Serve and generate a new code for full access - later token rotation/revocation remains bounded by both the device's approved role contract and the caller session's operator scopes
Treat the setup code like a password while it is valid.
The iOS and Android Settings → Gateway pages show Full or Limited access. To upgrade a limited phone, first configure a secure wss:// or Tailscale Serve route, then generate a new full-access setup code, scan or paste it in that settings page, and reconnect.
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. Non-loopback plaintext routes receive limited access. 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. The setup command adds this fallback only for lan; custom and tailnet keep their explicitly advertised routes. The iOS app probes the advertised routes in order and saves the first reachable endpoint.
Approve a node device
openclaw devices list
openclaw devices approve <requestId>
openclaw devices reject <requestId>
If an explicit approval is rejected because the approving paired device session was opened with pairing-only scope, the CLI resends the same request using operator.admin. This allows an existing admin-capable paired device to establish a new Control UI or browser pairing without manually editing the pairing store. The Gateway still validates the retried connection; tokens that cannot authenticate with operator.admin remain blocked.
When the same device retries with different authentication details (such as different role, scopes, or public key), the previous pending request is replaced and a new requestId is created.
Note
An already paired device does not gain broader access silently. If it reconnects requesting more scopes or a wider role, OpenClaw keeps the existing approval unchanged and generates a new pending upgrade request. Use
openclaw devices listto compare the currently approved access with the newly requested access before you approve.
Optional trusted-CIDR node auto-approve
Device pairing is manual by default. For tightly controlled node networks, you can enable first-time node auto-approval with specific CIDRs or exact IPs:
{
gateway: {
nodes: {
pairing: {
autoApproveCidrs: ["192.168.1.0/24"],
},
},
},
}
This applies only to fresh role: node pairing requests that have no requested scopes. Operator, browser, Control UI, and WebChat clients still require manual approval. Changes to role, scope, metadata, and public key still require manual approval.
Node pairing state storage
Stored in the shared SQLite state database at ~/.openclaw/state/openclaw.sqlite:
- pending device pairing requests (short-lived; they expire after 5 minutes)
- paired devices and tokens
Older gateways kept this state in ~/.openclaw/devices/*.json; those files are imported into SQLite at gateway startup and archived with a .migrated suffix.
Notes
- The
node.pair.*API (CLI:openclaw nodes pending|approve|reject|remove|rename) manages node capability approvals stored on the same paired device records. WS nodes still require device pairing; see Node pairing. - The pairing record is the authoritative source for approved roles. Active device tokens remain bound to that approved role set; a stray token entry outside the approved roles does not create new access.