feat: add device token auth and devices cli

This commit is contained in:
Peter Steinberger
2026-01-20 10:29:13 +00:00
parent 1c02de1309
commit d88b239d3c
27 changed files with 1055 additions and 71 deletions

66
docs/cli/devices.md Normal file
View File

@@ -0,0 +1,66 @@
---
summary: "CLI reference for `clawdbot devices` (device pairing + token rotation/revocation)"
read_when:
- You are approving device pairing requests
- You need to rotate or revoke device tokens
---
# `clawdbot devices`
Manage device pairing requests and device-scoped tokens.
## Commands
### `clawdbot devices list`
List pending pairing requests and paired devices.
```
clawdbot devices list
clawdbot devices list --json
```
### `clawdbot devices approve <requestId>`
Approve a pending device pairing request.
```
clawdbot devices approve <requestId>
```
### `clawdbot devices reject <requestId>`
Reject a pending device pairing request.
```
clawdbot devices reject <requestId>
```
### `clawdbot devices rotate --device <id> --role <role> [--scope <scope...>]`
Rotate a device token for a specific role (optionally updating scopes).
```
clawdbot devices rotate --device <deviceId> --role operator --scope operator.read --scope operator.write
```
### `clawdbot devices revoke --device <id> --role <role>`
Revoke a device token for a specific role.
```
clawdbot devices revoke --device <deviceId> --role node
```
## Common options
- `--url <url>`: Gateway WebSocket URL (defaults to `gateway.remote.url` when configured).
- `--token <token>`: Gateway token (if required).
- `--password <password>`: Gateway password (password auth).
- `--timeout <ms>`: RPC timeout.
- `--json`: JSON output (recommended for scripting).
## Notes
- Token rotation returns a new token (sensitive). Treat it like a secret.
- These commands require `operator.pairing` (or `operator.admin`) scope.

View File

@@ -116,17 +116,18 @@ clawdbot gateway call logs.tail --params '{"sinceMs": 60000}'
## Discover gateways (Bonjour)
`gateway discover` scans for Gateway bridge beacons (`_clawdbot-bridge._tcp`).
`gateway discover` scans for Gateway beacons (`_clawdbot-gateway._tcp`).
- Multicast DNS-SD: `local.`
- Unicast DNS-SD (Wide-Area Bonjour): `clawdbot.internal.` (requires split DNS + DNS server; see [/gateway/bonjour](/gateway/bonjour))
Only gateways with the **bridge enabled** will advertise the discovery beacon.
Only gateways with Bonjour discovery enabled (default) advertise the beacon.
Wide-Area discovery records include (TXT):
- `gatewayPort` (WebSocket port, usually `18789`)
- `sshPort` (SSH port; defaults to `22` if not present)
- `tailnetDns` (MagicDNS hostname, when available)
- `gatewayTls` / `gatewayTlsSha256` (TLS enabled + cert fingerprint)
- `cliPath` (optional hint for remote installs)
### `gateway discover`

View File

@@ -34,6 +34,7 @@ This page describes the current CLI behavior. If commands change, update this do
- [`models`](/cli/models)
- [`memory`](/cli/memory)
- [`nodes`](/cli/nodes)
- [`devices`](/cli/devices)
- [`node`](/cli/node)
- [`approvals`](/cli/approvals)
- [`sandbox`](/cli/sandbox)
@@ -188,6 +189,7 @@ clawdbot [--dev] [--profile <name>] <command>
runs
run
nodes
devices
node
start
daemon

View File

@@ -2677,7 +2677,7 @@ Notes:
Auth and Tailscale:
- `gateway.auth.mode` sets the handshake requirements (`token` or `password`).
- `gateway.auth.token` stores the shared token for token auth (used by the CLI on the same machine).
- `gateway.auth.token` stores the shared token for token auth (used by the CLI on the same machine and as the bootstrap credential for device pairing).
- When `gateway.auth.mode` is set, only that method is accepted (plus optional Tailscale headers).
- `gateway.auth.password` can be set here, or via `CLAWDBOT_GATEWAY_PASSWORD` (recommended).
- `gateway.auth.allowTailscale` allows Tailscale Serve identity headers
@@ -2686,6 +2686,9 @@ Auth and Tailscale:
`true`, Serve requests do not need a token/password; set `false` to require
explicit credentials. Defaults to `true` when `tailscale.mode = "serve"` and
auth mode is not `password`.
- After pairing, the Gateway issues **device tokens** scoped to the device role + scopes.
These are returned in `hello-ok.auth.deviceToken`; clients should persist and reuse them
instead of the shared token. Rotate/revoke via `device.token.rotate`/`device.token.revoke`.
- `gateway.tailscale.mode: "serve"` uses Tailscale Serve (tailnet only, loopback bind).
- `gateway.tailscale.mode: "funnel"` exposes the dashboard publicly; requires auth.
- `gateway.tailscale.resetOnExit` resets Serve/Funnel config on shutdown.

View File

@@ -59,6 +59,18 @@ Gateway → Client:
}
```
When a device token is issued, `hello-ok` also includes:
```json
{
"auth": {
"deviceToken": "…",
"role": "operator",
"scopes": ["operator.read", "operator.write"]
}
}
```
### Node example
```json
@@ -141,6 +153,11 @@ The Gateway treats these as **claims** and enforces server-side allowlists.
- If `CLAWDBOT_GATEWAY_TOKEN` (or `--token`) is set, `connect.params.auth.token`
must match or the socket is closed.
- After pairing, the Gateway issues a **device token** scoped to the connection
role + scopes. It is returned in `hello-ok.auth.deviceToken` and should be
persisted by the client for future connects.
- Device tokens can be rotated/revoked via `device.token.rotate` and
`device.token.revoke` (requires `operator.pairing` scope).
## Device identity + pairing