Device Pairing
How the DB-backed pairing system authorises users across all gateways.
Overview
Org in a Box uses a DB-backed pairing system instead of static allowlists. When an unknown user messages any gateway, they receive a one-time pairing code. The owner approves via the web admin panel or CLI — no .env editing required.
How It Works
Unknown user sends DM to bot
↓
Gateway checks gateway_paired_users — not found
↓
Rate limit check (1 code/user/10 min, max 3 pending/gateway)
↓
Insert gateway_pairing_codes (code, expires_at = now + 1h)
↓
NOTIFY orginabox_gateway_events → SSE pushes to admin/wizard
↓
Bot replies: "Your Telegram ID: 123456789 · Your pairing code: ABCD1234"
Owner approves (web or CLI)
↓
gateway_pairing_codes.consumed_at = now (atomic transaction)
gateway_paired_users row inserted
↓
NOTIFY → wizard auto-advances to Done · admin table updates live
Next message from same user
↓
gateway_paired_users check passes → agent-turn job enqueued
Code Properties
| Property | Value |
|---|---|
| Length | 8 characters |
| Alphabet | ABCDEFGHJKLMNPQRSTUVWXYZ23456789 (no 0/O/1/I ambiguous chars) |
| TTL | 1 hour |
| Rate limit | 1 new code per user per 10 minutes (including already-approved codes) |
| Max pending | 3 per gateway total |
| Storage | gateway_pairing_codes Postgres table |
Approval Channels
Web wizard (first-time setup)
/onboarding/3 — SSE stream from /v1/gateways/:id/events. Code appears automatically when the user messages the bot. One-click Approve auto-advances to Done.
Web admin (ongoing)
/admin/gateways → expand "Pending Requests" — live-updating table with Approve/Reject buttons.
CLI
# List pending codes
oiab gateway pairing-list
# Approve by code (gateway auto-detected from code)
oiab gateway pairing-approve --code ABCD1234
# Approve with explicit gateway
oiab gateway pairing-approve --gateway <uuid> --code ABCD1234
Managing Paired Users
# List all gateways with paired user counts
oiab gateway list
# Revoke a specific user
oiab gateway pairing-revoke --gateway <uuid> --user 123456789
Via web: /admin/gateways → expand "Paired Users" → click Revoke.
Database Tables
| Table | Purpose |
|---|---|
gateway_configs | One row per gateway (bot token encrypted, webhook secret encrypted) |
gateway_paired_users | Approved (gateway_id, external_user_id) pairs |
gateway_pairing_codes | Pending codes with TTL and consumed-at tracking |
Legacy Fallback
When GATEWAY_ID is not set in the gateway container's environment, pairing is skipped and all users are accepted (old behaviour). Set GATEWAY_ID to enforce pairing.
TELEGRAM_ALLOWED_USER_IDS still works as a secondary allowlist and is checked after the DB pairing table.
