Skip to content

Device Credentials

A device is a physical or soft phone that registers to the platform and rings when its line is called. Declaring devices and binding them to lines is config work, covered in Lines; this page covers the one piece of device state that lives outside the config document: the SIP digest credential each device authenticates with. The API surface is deliberately small — two verbs on one endpoint — but the lifecycle around it has rules worth knowing.

Conventions as usual: $VSS, $TOKEN for curl; a configured vsscli profile. Peer commands are top-level (vsscli peer …) — unlike voicemail and line features they are not namespace-scoped, because the peer key itself identifies the tenant.

Every device in an applied config becomes a SIP peer whose key is:

<device-name>@<sip-realm>

sip-realm is the namespace-level realm from the config’s configuration: block. The realm is what lets tenants share device and extension names — alice-desk@pbx.acme.example and alice-desk@pbx.other.example are different peers — and it is the realm your devices must be configured to authenticate against.

The credential lifecycle is tied to config applies:

  • Apply that adds a device → the peer row is created without a credential. A device cannot register until a password is minted through the endpoints below — new devices are dark by default, mirroring the no-default-PIN stance voicemail takes.
  • Apply that removes a device → the peer row is deleted, and deliberately in auth-before-routing order: a removed device loses the ability to authenticate before anything else is torn down. There is no orphan state to clean up.
  • Password writes never touch config — no version, no apply, effective on their own.

The server stores only the digest hash (HA1), never the cleartext. There is consequently no “read password” endpoint and no recovery: a lost device password is replaced, not retrieved.

Credential writes are gated by the peer:setpass action, held by partition-admin, namespace-admin, and provisioner. A peer is authorized against its owning namespace, the same way a line is, so a grant qualifies when it covers that namespace:

  • A namespace-scoped grant works for peers in that namespace (or any descendant — subtree breadth applies, just like line and voicemail authorization). A namespace-scoped provisioner or namespace-admin can mint credentials for the devices in their own namespace(s).
  • A partition- or system-scoped grant works for every peer in that partition. Use this for a central device-provisioning credential.
  • operator/editor deliberately do not carry the action — a peer credential change can knock a registered device offline, so it stays with the admin/provisioning roles.

Two practical recipes — a namespace provisioner for one tenant, or a partition-wide provisioning credential:

Terminal window
vsscli user grant add <prov-user-id> --role provisioner --scope ns:$NSID
vsscli user grant add <prov-user-id> --role provisioner --scope pt:$PTID

Two ways to set a password. Generate is preferred — the server mints a strong random passphrase and returns it exactly once:

Terminal window
curl -s -X POST "$VSS/v1/peer/alice-desk@pbx.acme.example/setpass" \
-H "Authorization: Bearer $TOKEN"
# → {"success":true,"password":"kD8mQv2xT9wRfLpN3sJh"}

Capture password from the response — it is not stored and cannot be shown again.

Set stores a password you chose — for staged provisioning systems that pre-print credentials or phones with fixed passwords:

Terminal window
curl -s -X PUT "$VSS/v1/peer/alice-desk@pbx.acme.example/setpass" \
-H "Authorization: Bearer $TOKEN" -d '{"password":"chosen-by-you"}'
# → 204 No Content

Both verbs are also the rotation path — setting a password on a peer that already has one simply replaces it.

The device then registers with:

Setting on the phone Value
Username / auth user The device name (alice-desk)
Realm / domain The namespace’s sip-realm
Password What you just minted
Registrar / proxy The namespace’s anycast IP

Rotation semantics — what happens to a live device

Section titled “Rotation semantics — what happens to a live device”
  • The new password works immediately. Edge proxies verify against the stored HA1, fetching it on demand.
  • The old password can linger for up to ~5 minutes. Each edge node keeps a short-lived credential cache (5-minute expiry); a device re-authenticating with the old password against a node that still holds the old hash will succeed until that cache entry expires. Rotation is therefore fast but not instant revocation.
  • Registrations don’t drop on rotation. An existing registration stays valid until it expires; the device feels the change at its next re-REGISTER, when it must present the new password.

For a compromised credential, rotate immediately and treat the ~5-minute cache window as the exposure bound on the credential itself. To cut a device off entirely without touching config, revoke the credential (below); to remove the device altogether, delete it from the config and apply.

Revoke resets the stored HA1 to empty. An empty credential can never authenticate (the auth path fails closed on an empty secret), so revoke is the way to disable a lost or compromised device without editing and re-applying config. Setting a new password later re-enables it.

Terminal window
curl -s -X PUT "$VSS/v1/peer/alice-desk@pbx.acme.example/setpass?clear=true" \
-H "Authorization: Bearer $TOKEN"
# → 204 No Content (no request body)

Revoke is subject to the same ~5-minute edge cache window as rotation: a node still holding the old hash will accept the old password until its cache entry expires. The difference from rotation is that no valid credential exists afterward — nothing can register as the device until you mint a new one. Same peer:setpass permission as setting a password.

Terminal window
# 1. Config: declare the device and bind it to a line (then apply)
# devices:
# alice-desk:
# line: "1001"
# lines:
# "1001":
# devices: [alice-desk]
# 2. Mint its credential
vsscli peer password generate alice-desk@pbx.acme.example --out alice-desk.cred
# 3. Configure the phone (username / realm / password / registrar) and
# watch it register; then place a test call in each direction.

Order matters only in one direction: the peer must exist (step 1 applied) before step 2 — setpass on an unknown peer is a 404, it never creates one.

Response / symptom Meaning Do
400 invalid peer key The {peer} path segment isn’t name@realm Include the realm — the bare device name is not a peer key
404 SIP peer not found No such peer row The device isn’t in an applied config yet, was removed, or the realm half doesn’t match the namespace’s sip-realm
401 on setpass The caller’s grant doesn’t cover the peer’s owning namespace, or the role lacks peer:setpass (e.g. operator/editor) Grant provisioner/namespace-admin on the peer’s namespace (ns:$NSID), or a partition grant (pt:$PTID) that contains it
Old password still registers after rotation Per-edge credential cache Expected for up to ~5 minutes; see rotation semantics above
Device won’t register with a fresh credential Realm mismatch is the usual culprit The phone must send the device name as auth user and the namespace’s exact sip-realm as realm/domain