Pairing in OpenClaw: DM and Node Access Approval
Learn how OpenClaw pairing controls who can DM the bot and which nodes join the network. Essential for gateway administrators and channel managers.
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 (determines who may message the bot)
- Node pairing (decides which devices/nodes can join the gateway network)
Security details: Security
1) DM pairing (inbound chat access)
If a channel is set up with the DM policy pairing, messages from unknown senders are held back and paired with a short code. They stay unprocessed until you give the go-ahead.
The default DM policies are listed in: Security
dmPolicy: "open" becomes publicly visible only when the effective DM allowlist contains "*". For public-open setups, that wildcard is a prerequisite during configuration and validation. Should existing state hold open with specific allowFrom entries, the runtime continues to admit only those senders, and approvals recorded in the pairing store do not expand open access.
Pairing codes:
- 8 characters, uppercase, excluding ambiguous characters (
0O1I). - Valid for 1 hour. The bot dispatches the pairing message only when a fresh request appears, roughly once per hour per sender.
- Pending DM pairing requests are limited to 3 per channel account; extra requests are disregarded until one is either approved or lapses.
Approve from the Control UI
Go to Settings → Channels → DM access requests. This queue aggregates pending requests from all configured channel accounts whose DM policy is pairing. You can filter by channel or account, inspect the sender ID and metadata, then hit Approve.
Approval covers direct-message access only, not group access. When supported, the approval dialog presents these explicit choices:
- Notify the requester after approval
- Also make this sender the first command owner, visible only if no command owner exists and the Control UI session has
operator.admin
Select Dismiss to drop a pending request without approving it. Dismissal isn't a lasting block; the sender can ask for access again at a later time.
Approve from the CLI
openclaw pairing list telegram
openclaw pairing approve telegram <CODE>
Add --notify to notify the requester on the same channel. For multi-account channels, use --account <id>.
Unlike the Control UI's explicit checkbox, the CLI automatically sets up commands.ownerAllowFrom when no command owner is configured, using an entry like telegram:123456789. This ensures first-time installations have a clear owner for privileged commands and exec approval prompts. Once an owner is in place, subsequent pairing approvals grant only DM access, never additional owners.
Note
WhatsApp's login QR ties a WhatsApp account to OpenClaw. DM access requests approve individuals messaging that account. These are distinct 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 the top-level accessGroups when the same trusted sender set should span multiple message channels or apply to both DM and group allowlists.
Static groups rely on type: "message.senders" and are referenced via 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"] },
},
}
Full documentation on access groups is available here: Access groups
Where the state lives
Kept 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:
- every request and approved sender is tied to a channel and account
- the runtime reads only the canonical SQLite rows, ignoring legacy files
Older gateways stored <channel>-pairing.json and <channel>-<accountId>-allowFrom.json under ~/.openclaw/credentials/. On startup, migration and openclaw doctor --fix bring those files into SQLite and delete each source after a successful import. Treat the SQLite database as sensitive, since these rows control access to your assistant.
Note
The pairing allowlist store handles DM access only. Group authorization is a separate matter. Approving a DM pairing code does not automatically let that sender execute group commands or manage 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 using role: node. The Gateway generates a device pairing request that needs approval.
Pair from the Control UI (recommended)
Use a Control UI session that is already connected and has operator.admin access:
- Launch the Control UI and navigate to Settings → Devices.
- From the Devices page, select Pair device.
- Leave Full access (recommended) as is, or pick Limited access to exclude administrative Gateway controls.
- Press Create setup code.
- On your phone, go to the OpenClaw app → Settings → Gateway.
- Either scan the QR code or input the setup code, then establish the connection.
The official OpenClaw iOS and Android applications receive automatic approval when their setup-code metadata aligns. When Pending approval displays a request (such as for a non-official client or metadata that does not match), check its role and scopes prior to granting approval.
If the current Control UI session lacks administrator access, the button stays disabled. In that situation, fall back to the CLI approval flow described below, run from the Gateway host.
Pair via Telegram
First-time device pairing can be handled entirely through Telegram when the
device-pair plugin is in use:
- Send this to your bot in Telegram:
/pair - The bot responds with two messages: one containing instructions and a separate setup code message (which is straightforward to copy/paste in Telegram).
- On your phone, open the OpenClaw iOS app → Settings → Gateway.
- Connect by scanning the QR code (
/pair qr) or pasting the setup code. - The official mobile app connects without further action. If
/pair pendingpresents a request, examine its role and scopes before approving.
The setup code consists of a base64-encoded JSON payload holding:
url: the Gateway WebSocket URL (eitherws://...orwss://...)urls: the ordered LAN/Tailnet routes the mobile app can attempt, when they are availablebootstrapToken: a bootstrap token valid for a single use during the initial pairing handshake; the Gateway expires it after 10 minutes
Once pairing is complete, run /pair cleanup to invalidate any setup codes that were not used.
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 remainsscopes: [] - the default handed-off
operatortoken includesoperator.admin,operator.approvals,operator.read,operator.talk.secrets, andoperator.write - Control UI Limited access and
openclaw qr --limitedleave outoperator.adminwhile preserving the other operator scopes - plaintext LAN
ws://setup automatically applies the same limited profile; for full access, configurewss://or Tailscale Serve and generate a fresh code - later token rotation/revocation stays constrained by both the device's approved role contract and the caller session's operator scopes
While a setup code remains valid, treat it with the same care as a password.
The Settings → Gateway pages on iOS and Android indicate Full or Limited
access. To move a limited phone up, first set up a secure wss:// or
Tailscale Serve route, then generate a new full-access setup code, scan or paste
it into that settings page, and reconnect.
For Tailscale, public, or other remote mobile pairing, rely on Tailscale Serve/Funnel
or another wss:// Gateway URL. Plaintext ws:// setup codes are only
accepted for loopback, private LAN addresses, .local Bonjour hosts, and the Android
emulator host. Non-loopback plaintext routes get limited access. Tailnet
CGNAT addresses, .ts.net names, and public hosts still fail closed before
QR/setup-code issuance.
OpenClaw only advertises Tailscale setup URLs when it owns the route through
gateway.tailscale.mode=serve|funnel. Legacy external Serve routes that proxy a
gateway.bind=lan listener are not advertised, since the ordinary listener
rejects Tailscale-shaped proxy ingress. Run openclaw doctor to preview the
safe default-route migration, then openclaw doctor --fix and restart the
Gateway. Custom Serve ports and Tailscale Services need manual migration.
For a retired gateway.tailscale.serviceName config, Doctor disables managed
ingress and prints the command needed to clear the retained Service route.
Approve a node device
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 allows an existing admin-capable paired device to recover a new
Control UI/browser pairing without manually editing the pairing store. 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.
Note
An already paired device does not get broader access silently. If it reconnects asking for more scopes or a broader role, OpenClaw keeps the existing approval as-is and creates a fresh 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 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.
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 + 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 durable source of truth for approved roles. Active device tokens stay bounded to that approved role set; a stray token entry outside the approved roles does not create new access.