Security
RBAC — roles and permissions
SIVO's access control model. 5 base roles, granular permissions, audited cross-tenant superadmin access.
Executive summary
SIVO uses RBAC (Role-Based Access Control) with 5 base roles. Every REST endpoint and dashboard action checks the JWT role before executing. There’s no “god mode”: even superadmin is audited in audit_logs when operating cross-tenant.
Base roles
| Role | Scope | Key capability |
|---|---|---|
| agent | Own profile + queue(s) | Handle calls, pause, view own call history |
| supervisor | Tenant-wide (read + live actions) | Wallboard, spy/whisper/barge, force pause, see all activity |
| admin | Tenant-wide (CRUD) | Manage agents, queues, IVR, DIDs, trunks, policies, integrations |
| superadmin | Cross-tenant | SIVO support operations, audited |
| viewer | Tenant-wide (read-only) | Queries, reports, exports — no changes |
Permission matrix by resource
| Resource | agent | supervisor | admin | superadmin |
|---|---|---|---|---|
| Own profile | R/W (limited) | R/W (limited) | R/W | R/W |
| Other tenant agents | R (basic) | R | R/W | R/W |
| Agents of another tenant | — | — | — | R/W (audited) |
| Queues — config | — | R | R/W | R/W |
| Queues — live actions (force pause, etc.) | — | W | W | W |
| IVR flows | — | R | R/W | R/W |
| DIDs and trunks | — | R | R/W | R/W |
| Recordings — listen | R (own) | R (all) | R | R |
| Recordings — download/delete | — | — | R/W | R/W |
| Transcripts | R (own) | R (all) | R | R |
| Webhooks | — | R | R/W | R/W |
| Salesforce integration | — | R | R/W | R/W |
| Audit logs | — | R | R | R |
| Tenant feature flags | — | — | — | R/W |
| Tenants (create, delete) | — | — | — | R/W |
How it is enforced
In the JWT
Each token carries the role signed RS256. No privilege escalation by modifying the token:
{
"sub": "uuid-of-user",
"tenantSlug": "acme",
"sipDomain": "acme.sip.sivocenter.com",
"role": "supervisor",
"iat": 1715000000,
"exp": 1715086400
}
On each REST endpoint
Each router mounts requireRole(...) middleware:
router.delete('/agents/:id', requireRole('admin', 'superadmin'), deleteAgentHandler);
If insufficient role: 403 Forbidden with code: INSUFFICIENT_ROLE.
In the dashboard
UI components conditional to role. But backend is the source of truth: even if the UI shows a button by bug, the endpoint rejects with 403.
In PostgreSQL (RLS)
SIVO roles ≠ PostgreSQL roles. What isolates data at the engine level are the RLS policies filtering by tenant_id (session variable app.current_tenant).
RBAC roles are orthogonal: they define what the user can do within their tenant, not which tenant they see.
The superadmin role (SIVO ops)
We operate SIVO. For support and troubleshooting there’s a superadmin role with cross-tenant access. Mitigations:
- Only 3-5 people max from the SIVO team have this role. Their accounts are subject to:
- Mandatory MFA (TOTP).
- Short sessions (8h).
- Quarterly password rotation.
- To operate on another tenant, they send
X-Tenant-Id: <tenant-uuid>header. Without it, they see nothing of other tenants. - Each use of the header is logged in
audit_logswithcross_tenant: trueflag. The customer sees this in their backoffice (“SIVO team access to your account”). - Some critical ops (mass export, tenant delete) require
pair-approval: two superadmins must confirm.
Custom permissions / Enterprise
For Enterprise customers needing custom roles (e.g. “QA reviewer can view recordings of certain queues but not others”):
- We define
permission_overridesper user in JSON. - Implemented with additional middleware after
requireRole. - Documented case by case, part of onboarding consulting.
What we intentionally DON’T do
- Per-user API keys to call the API. JWT is the only mechanism — 24h TTL, revocable, auditable.
- Permanent sessions. After 24h, login again.
- Sharing accounts between people. One account = one person. Enforced with MFA + unique email.
Rotate password
Each user can change their password from the top-right avatar → Profile → Change password. Rules:
- Min 8 characters.
- Cannot equal the hash of last 5.
- Temp lockout after 5 failures (15 min).
Admin/superadmin can force reset any user’s password. The user gets an email with a one-time link (1h TTL).
Support
[email protected] — for vulnerability reports or suspected role misuse.