People, devices and roles
client.people, the People namespace, lets an Admin manage the tenant’s people. An Admin can:
- see who holds a role, and what devices and AI agents each person has
- give and remove roles
- revoke devices and offboard people
An Owner can also map a group to a role.
A role carries no key. Giving someone the Admin role, or mapping a group to Employee, changes what they may ask for. It gives no access beyond the key domains they are already a member of.
The calls
The samples use the allowed helper from Access decisions.
const people = await client.people.list();// [{ person, roles: [{ role, through }], organization, devices, agents }, ...]
const devices = await client.people.devices(alice);
await allowed(await client.people.revoke(recipientId, 'lost'));await allowed(await client.people.revoke(recipientId, 'stolen'));await allowed(await client.people.revoke(recipientId, 'retired'));
const left = await allowed(await client.people.offboard(bob));if (left?.ownerlessDomains.length) tell('Domains bob alone owned wait for break-glass');
await allowed(await client.people.changeRole(carol, 'admin', 'give'));await allowed(await client.people.changeRole(carol, 'admin', 'remove'));
await allowed(await client.people.mapGroup('clinicians', 'employee'));await allowed(await client.people.unmapGroup('clinicians'));let people = try await client.people.list()let devices = try await client.people.devices(alice)
_ = try await allowed(client.people.revoke(recipientId, reason: .stolen))
let ownerless = try await allowed(client.people.offboard(bob))if let ownerless, !ownerless.isEmpty { tell("Domains bob alone owned wait for break-glass") }
_ = try await allowed(client.people.changeRole(carol, role: "admin", change: .give))_ = try await allowed(client.people.changeRole(carol, role: "admin", change: .remove))_ = try await allowed(client.people.mapGroup("clinicians", role: "employee"))_ = try await allowed(client.people.unmapGroup("clinicians"))val people = client.people.list()val devices = client.people.devices(alice)
allowed(client.people.revoke(recipientId, reason = RevocationReason.STOLEN))
val ownerless = allowed(client.people.offboard(bob))if (ownerless?.isNotEmpty() == true) tell("Domains bob alone owned wait for break-glass")
allowed(client.people.changeRole(carol, role = "admin", change = Change.GIVE))allowed(client.people.changeRole(carol, role = "admin", change = Change.REMOVE))allowed(client.people.mapGroup("clinicians", role = "employee"))allowed(client.people.unmapGroup("clinicians"))Each TenantPerson entry carries:
roles: each role the person holds, directly orthrougha grouporganizationdevices: the person’s device certificates (cards), asCardvaluesagents: every AI agent the person delegated to
What the SDK does for you
- Signs a revoke, an offboard or a role change after a fresh multi-factor sign-in. A revoke applies in one step: the card is withdrawn, its sessions end and the device loses all access.
- Refuses to let anyone revoke the device they call from.
- Refuses a change to the caller’s own roles. Nobody gives or removes their own.
- On
offboard, lists every key domain that only the leaver owned, asownerlessDomains. Hand these to break-glass recovery. - Refuses to map a group to Owner or Admin with
mapGroup. Those roles always go to one person at a time. - Raises
device-revokedwith theRevocationReasonon every other device of the tenant. - Raises
roleson a device whose person’s roles changed.
Decisions and errors you may see
Outcome or ErrorCode | When | What to do |
|---|---|---|
deny on revoke | The caller asked to revoke the device they are calling from. | Revoke from another of that person’s devices, or another Admin’s. |
deny on changeRole | The caller asked to change their own role. | Ask another Owner or Admin to make the change. |
challenge | The caller’s multi-factor sign-in is no longer fresh. | Call stepUp(), or use the allowed helper. |
not-found | The person or device named no longer exists in the tenant. | Refresh people.list() and try again. |