Skip to content

Operations: Pair a device

For the user-facing pairing flows, see Devices / Pairing. This page covers the admin/operator perspective: when an admin needs to pair a Device on a user's behalf, troubleshoot a stuck pair, or pair a service Device.

Admin pair-on-behalf

Status: target state. There is no UI today for an admin to start a pair flow on behalf of another principal. The CLI is the workaround.

If an admin must pair a Device for a user (e.g., support scenario):

  1. The user's principal must already exist (they have signed in once).
  2. The user's Space must exist (created on first login).
  3. The Device runs hivecast login --device --cloud https://hivecast.ai. The user code must be approved by the user (or by the admin on the user's behalf, which requires a session for the user — anti-pattern, avoid).

A clean admin pair-on-behalf op (auth.device.adminApprove or similar) is target state. Today, the user must be involved in approval.

Self-pair (platform Host paired to itself)

The platform Host can be paired to itself for self-test purposes — useful when verifying the pair flow end-to-end without a separate Device.

  1. On the platform Host: hivecast login --device --cloud http://127.0.0.1:3100.
  2. CLI prints user code, navigates browser to local /auth/link?userCode=<code>.
  3. Approve via the local-client identity (loopback bypasses auth).
  4. CLI exchanges; persists hivecast-link.json to the same <host-home>.

The platform Host is now paired to itself. Useful for development; not a production operation.

Service Device pairing

Status: target state. A service Device (a non-human-owned compute participant — bot, integration) requires ownerType: 'service' on its Space, which is schema-only.

The workaround: pair a regular Device under a dedicated principal that exists for service use only. That principal's Space carries ownerType: 'principal' (not 'service'); the distinction is operator-discipline rather than enforced.

Diagnosing a stuck pair

If a pair flow is stuck (auth.device.poll returns authorization_pending indefinitely):

bash
# Inspect the pending device-flow record
matrix invoke system.auth auth.device.status \
  '{"userCode":"<code>"}'
# Status fields: pending | approved | namespace_required | exchanged | cancelled

# If status is namespace_required:
# The principal does not own a Space with a matching public namespace claim.
# Either claim one or change the routeKey on the device-start.
matrix invoke system.auth auth.namespace.list '{"principalId":"p_xxx"}'
matrix invoke system.auth auth.namespace.claim '{...}'

# If status is pending:
# The user simply hasn't approved yet. Check whether they navigated to the
# correct activation URL.

# If the user code is invalid or expired:
# Cancel and start fresh.
matrix invoke system.auth auth.device.cancel '{"userCode":"<code>"}'

Diagnosing a stuck approval

If the user clicked Approve but the CLI's auth.device.poll still says authorization_pending:

  • The approval may have failed. Check the platform's system-auth runtime log.
  • The principal that approved may not own a Space with the requested routeKey. Look for namespace_required status.
bash
matrix invoke system.auth auth.hostLink.list '{"principalId":"p_xxx"}'
# Confirm the new Host Link appears, status: 'active'.

matrix invoke system.devices devices.list '{"principalId":"p_xxx"}'
# Confirm the Device shows up. May lag by ~30s after pair.

Authorization

A normal pair op (device-flow or pair-flow) requires:

  • Approval call: a signed-in principal whose own Spaces match the requested routeKey. The principal cannot approve into another principal's Space.
  • Exchange call: anyone holding the correct deviceCode (CLI) or pairRequestId + approvalCode (browser). These codes are short-lived and single-use.

There is no "admin override" for these checks today. Target state.

See also

Source: projects/matrix-3/packages/system-auth/src/index.ts:882-1196 for the pair/device ops.