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:

  1. DM pairing (determines who may message the bot)
  2. 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 example groupAllowFrom, 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:

  1. Launch the Control UI and navigate to Settings → Devices.
  2. From the Devices page, select Pair device.
  3. Leave Full access (recommended) as is, or pick Limited access to exclude administrative Gateway controls.
  4. Press Create setup code.
  5. On your phone, go to the OpenClaw app → SettingsGateway.
  6. 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:

  1. Send this to your bot in Telegram: /pair
  2. The bot responds with two messages: one containing instructions and a separate setup code message (which is straightforward to copy/paste in Telegram).
  3. On your phone, open the OpenClaw iOS app → Settings → Gateway.
  4. Connect by scanning the QR code (/pair qr) or pasting the setup code.
  5. The official mobile app connects without further action. If /pair pending presents 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 (either ws://... or wss://...)
  • urls: the ordered LAN/Tailnet routes the mobile app can attempt, when they are available
  • bootstrapToken: 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 to node plus full native-mobile operator access
  • the handed-off node token remains scopes: []
  • the default handed-off operator token includes operator.admin, operator.approvals, operator.read, operator.talk.secrets, and operator.write
  • Control UI Limited access and openclaw qr --limited leave out operator.admin while preserving the other operator scopes
  • plaintext LAN ws:// setup automatically applies the same limited profile; for full access, configure wss:// 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 list to 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.
1,771 words · updated Aug 22, 2026