Identity & Sign-InRoles & Permissions (RBAC)
On this page0

Unfamiliar word? See Glossary: words used in these docs. Looking for the tasks in order? Begin at Start Here.

Reference

Included in: All plans. Which Plan Includes What

Roles & Permissions (RBAC)

Who can see and do what in your instance is decided by roles and permissions (role-based access control, RBAC).

What It Does

An administrator shapes access on three screens under Administration: Roles, Groups and Access Control. The diagram shows how a permission, a role and a group fit together.

Apply a persona template and the access matrix recomputes: each resource row shows granted or denied for that role.ACCESS CONTROL MATRIX · RBACAPPLY PERSONASales RepFinance AnalystPeople Ops▸PEOPLE OPS — EFFECTIVE ACCESSCRMDENIEDBillingGRANTEDHR dataDENIEDCloudDENIEDAudit logsGRANTED

How Access Is Decided

A person’s effective permissions are everything granted by the roles they hold directly, plus the roles they inherit from the groups they are in, combined with any direct grants made to them individually. Roles are the normal path; a direct grant is the exception you make for one person without inventing a new role.

A group is a set of people. A role can be attached to a group, and every member then holds that role for as long as they are in the group (resolved live from group membership, not copied onto the person). A group also carries an MFA policy. A persona is a provisioning template for a job function, and it can optionally list Zonitix groups and roles. When the persona is applied — on user creation, onboarding or a role change — the person is added to those groups and roles, on top of the baseline. The same limit applies as everywhere else: an administrator cannot use a persona to give access they do not hold themselves.

If something here is not working as you expect, start with When something goes wrong.

The plain explanation is above. This part is for IT and developers: the exact settings, permission names, API addresses and data fields behind it. Closed: select the heading above to open it. While it is closed, your browser’s find-on-page (Ctrl+F or Cmd+F) does not search this part.

Built-In Roles

Setup seeds these. They are ordinary roles — rename them, change their permissions, or ignore them and build your own.

RoleWhat it is for
administratorFull system access
standard_userBaseline access for all employees
hr_managerManage recruitment and employee lifecycle. Also holds the employee-record permissions: view and edit employee files, view and add compensation, build the payroll hand-off file, people reports, leave, review cycles, training and surveys (bound to the HR Managers group)
hr_employeeHR employee: view users, view employee files, start onboarding/offboarding runs, manage personas (bound to the Human Resources group)
manager_approverApprove onboarding/workflow steps and access requests for anyone in the organisation (not limited to their own reports), and decide the access-review items assigned to them (bound to the Manager group)
recruiting_coordinatorHandle scheduling and logistics
sourcerFind and add candidates to top of funnel
hiring_managerReview candidates and submit scorecards
interviewerParticipate in interviews and submit scorecards
executive_reviewerFinal sign-off on anonymised candidate packets
finance_managerFinancial reconciliation, AI insights
finance_opsFinance operations: view spend, manage budgets, submit invoices (bound to the Finance group)
finance_approverFinance approver/controller: approve and pay invoices, approve budgets, close the period
One further roleBelongs to an optional add-on and is not described in these pages. Your Roles page lists it with the others.
security_analystMonitor compliance and Security Lab findings. Also holds manage_security (Security Settings), so assign it deliberately. Holds manage_employee_training and manage_phishing_simulation as well
security_compliance_viewerRead-only security & compliance visibility: read findings and logs, run scans (bound to the Security & Compliance group)
it_operationsIT staff: own persona blueprints without user or security admin (bound to the IT group)
cloud_architectOversee cloud infrastructure and resource mapping
integration_managerManage external integrations and identity hooks

Operating RBAC — The API

Everything above is the model; this section is how you actually change it. Every route below is served by the user-management service behind the gateway, so the public path is prefixed /api/v1/user-management and every call needs a valid session (Authorization: Bearer <jwt>) that carries the listed permission. There is no separate RBAC console API — these are the same endpoints the dashboard’s Roles, Groups and Permissions screens call. Two things hold across all of them: writes replace, they do not merge (userIds, groupIds and permissionIds set the entire membership, group binding or permission set, so anything in a list you send that you omit is removed), and the subset invariant in its own section below gates every grant.

Roles

MethodPathPurposeAuth
GET/api/v1/user-management/rolesList every role with its permissions, member IDs (IDs only, not full profiles) and the groups it is attached to (id and name)view_roles · manage_roles · view_dashboard
GET/api/v1/user-management/roles/:id/membersFull labelled roster of one role (names/emails) for the Edit Role dialogview_roles · manage_roles
POST/api/v1/user-management/rolesCreate a role and optionally seed its permissions, members and attached groups in one callmanage_roles
PUT/api/v1/user-management/roles/:idRename, re-describe, and replace the permission set, membership and/or attached groups of a rolemanage_roles
DELETE/api/v1/user-management/roles/:idDelete a role (the administrator role is protected and returns 403)manage_roles
POST/api/v1/user-management/roles/:roleId/permissionsReplace the full permission set of an existing rolemanage_roles

name is the only required field on create (it is unique and non-null); description, userIds, groupIds and permissionIds are optional. groupIds attaches the role to groups: every member of an attached group holds the role while they are in it (the dashboard calls this Assign to Groups). Like the other lists it is a full replacement, and GET /roles returns the current binding as Groups. Create returns 201 with the new role, update returns 200, delete returns 204, and POST /:roleId/permissions returns 200 { "ok": true }. A missing role is 404. A missing or blank name is 400 (Role name is required. on create, Role name cannot be blank. on update), and a name that is already in use is 409. The administrator role is special on every path: only a caller who already holds administrator may create it, rename into or out of it, change its membership (logged ADMIN_ROLE_MEMBERSHIP_CHANGED at critical severity), or change the groups attached to it (logged ADMIN_ROLE_GROUPS_CHANGED at critical severity, since every member of an attached group becomes an administrator); it always holds the entire catalog and cannot be deleted. A change that would leave it with no member, or remove the primary administrator or the caller from it, is refused with 403 and logged ADMIN_ROLE_LOCKOUT_BLOCKED (see the subset invariant below).

// Create a role with two permissions, one direct member and one attached group:

curl -X POST https://<your-instance>-api.zonitix.com/api/v1/user-management/roles \

-H "Authorization: Bearer $TOKEN" \

-H "Content-Type: application/json" \

-d '{ "name": "invoice_clerk", "description": "Submits invoices",

"permissionIds": [33, 35], "userIds": [42], "groupIds": [3] }'

// 201 Created → the new role. Logs ROLE_CREATED (info).


// Replace the whole permission set of role 7 (omitted permissions are removed):

curl -X POST https://<your-instance>-api.zonitix.com/api/v1/user-management/roles/7/permissions \

-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \

-d '{ "permissionIds": [11, 19] }'

// 200 { "ok": true }. Logs ROLE_PERMS_UPDATED (info).

The Permission Catalog & Per-User Direct Grants

MethodPathPurposeAuth
GET/api/v1/user-management/permissionsThe full catalog, each permission carrying its Roles[] and holder-user IDs (the org-wide who-holds-what map)manage_permissions · manage_roles
POST/api/v1/user-management/permissions/:id/assignmentsSet which roles and which individual users hold this one permission (the inverse join)manage_permissions

GET /permissions is deliberately not readable by the baseline view_dashboard role: it returns the list of who holds manage_security, pay_invoice and the rest — a social-engineering target list — so it is gated to RBAC admins. A user’s own effective access is derived from their JWT, not from this endpoint. POST /:id/assignments is the per-user direct-grant path: userIds writes rows straight into the user’s effective permissions (these land in the JWT), and roleIds writes the same role↔permission rows from the other side. Both are optional but both are full replacements of that permission’s user set and role set respectively — and the administrator role is always re-added afterwards, so it can never be stripped of a permission this way. Returns 200 { "ok": true }, or 404 if the permission id does not exist.

// Grant permission 29 directly to user 42, and also to role 5:

curl -X POST https://<your-instance>-api.zonitix.com/api/v1/user-management/permissions/29/assignments \

-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \

-d '{ "userIds": [42], "roleIds": [5] }'

// 200 { "ok": true }. Logs PERMISSION_ASSIGNMENT_UPDATED (info).

// Blocked with 403 if you do not yourself hold permission 29 (see the subset invariant).

Groups & MFA Policy

MethodPathPurposeAuth
GET/api/v1/user-management/groupsList groups with member IDs (IDs only)view_groups · manage_groups · view_dashboard
GET/api/v1/user-management/groups/:id/membersFull labelled roster of one groupview_groups · manage_groups · manage_roles
POST/api/v1/user-management/groupsCreate a group, optionally with members and an MFA policymanage_groups
PUT/api/v1/user-management/groups/:idRename/re-describe a group, set membership, set its MFA policymanage_groups
DELETE/api/v1/user-management/groups/:idDelete a groupmanage_groups

Groups organise people, pass on any role attached to them (see Roles above), and carry an MFA policy. The policy is the three-way mfaPolicy: inherit (follow the organisation-wide setting), require (every member must use MFA) or exempt. An exemption takes two more fields: mfaExemptUntil (an ISO date, or null for no end date) and mfaExemptReason; both are cleared when the policy leaves exempt. The older boolean requiresMfa is still accepted when mfaPolicy is not sent (true maps to require, false to inherit) and is kept mirrored on the group.

Writable fields are allow-listed — name, description, userIds — and the MFA fields are only honoured for a caller who also holds manage_security. A policy change is audited as its own event: MFA_EXEMPTION_GRANTED and MFA_EXEMPTION_REVOKED at warning severity, and MFA_POLICY_CHANGED (info) for a move between inherit and require. Create returns 201, update 200, delete 204; a missing group is 404 and a name that is already in use is 409. A membership change on a group that confers permissions the caller does not hold is 403 (see the subset invariant below). Deleting a group is audited as GROUP_DELETED at warning severity.

Be precise: who can change MFA enforcement

A plain manage_groups operator who sends mfaPolicy: "exempt" (or the legacy requiresMfa: false) does not weaken MFA — every MFA field is silently dropped from the write and the group keeps its current policy. This is deliberate: it stops a delegated group manager from downgrading a security control. Changing any of mfaPolicy, mfaExemptUntil, mfaExemptReason or requiresMfa requires manage_security. Inspector check: as a manage_groups-only caller, PUT a group with mfaPolicy: "exempt" and confirm the stored policy is unchanged.

Scoped Compliance Access

MethodPathPurposeAuth
POST/api/v1/user-management/permissions/compliance-access/:userIdGrant one user the scoped view_assigned_compliance permissionmanage_compliance
DELETE/api/v1/user-management/permissions/compliance-access/:userIdRevoke that scoped grant from the usermanage_compliance

These two are a narrow, fixed grant: they can only ever add or remove the single view_assigned_compliance permission (a direct user grant, so it touches only that one person), used when an auditor assigns or finalizes a compliance section. There is no body — the target is the :userId in the path. A missing user is 404; if view_assigned_compliance was never seeded, grant returns 400. Success is 200 { "ok": true }, logged COMPLIANCE_ACCESS_GRANTED / COMPLIANCE_ACCESS_REVOKED.

The Subset Invariant: You Cannot Confer What You Do Not Hold

This is the single most important control on the RBAC surface, and it is worth stating plainly because an earlier version of it failed by guarding one door of several. A non-administrator caller can never grant a permission they do not themselves hold — not by creating a role that carries it, not by editing a role into carrying it, not by replacing a role’s permission set, and not by assigning the permission from the permission side. The caller’s held set is resolved from the database (their roles’ permissions plus their own direct grants), never from the request header, because the gateway scopes that header per service. An administrator bypasses the check by design (it is root and holds everything), and an unidentifiable caller fails closed — it may grant nothing.

Guarded On Role Creation

POST /roles checks every id in permissionIds against the caller’s held set before the role is written. Excess permissions abort the whole transaction with 403 and a ROLE_ESCALATION_BLOCKED audit line (warn).

Guarded On Every Assignment Path

PUT /roles/:id, POST /roles/:roleId/permissions and POST /permissions/:id/assignments run the identical check. Adding members to a role whose permissions exceed yours is blocked too, and so is attaching a group to it with groupIds (every member of the group would inherit the role) — building the powerful role and then filling it is the same escalation, one step later. Both return 403 with You cannot assign members or groups to a role holding permissions you do not have.

Guarded On Group Membership

A group passes on every role attached to it, so adding someone to a group is also a grant. POST /groups and PUT /groups/:id refuse a membership change on a group that confers permissions the caller lacks: 403 with You cannot change membership of a group that grants access you don’t hold followed by the permission names, and a ROLE_ESCALATION_BLOCKED audit line (warn). A group with no role attached confers nothing, so ordinary group creation is unaffected.

The Administrator Role Cannot Be Emptied

A change to the administrator role’s members or attached groups is judged on who would still be an administrator afterwards, counting direct members and the members of every attached group. It is refused with 403, and audited as ADMIN_ROLE_LOCKOUT_BLOCKED (warn), if it would leave the role with no member, remove the primary administrator, or remove the caller. Adding people, or re-saving an unchanged list, is never refused.

Inspector verification

Sign in as an operator who holds manage_roles and manage_permissions but not manage_security. Look up that permission’s id from GET /permissions, then attempt to confer it four ways: create a role with it in permissionIds; PUT an existing role to add it; POST /roles/:roleId/permissions with it; and POST /permissions/<that id>/assignments with your own userIds. Each must return 403 { "error": "Privilege escalation blocked" } with a message naming the permission, and each must leave a ROLE_ESCALATION_BLOCKED (or PERMISSION_ESCALATION_BLOCKED) entry at warn severity in the audit log. If any of the four accepts the grant, the invariant is broken on that path.

Writes replace — omission removes

permissionIds, userIds and groupIds are not additive. Posting { "roleIds": [3] } to a permission removes it from every role except 3; replacing a role’s permissionIds drops any you leave out. To add without disturbing the rest, read the current set first and send the union.

Seeded Permission Catalog

Every atomic permission the platform seeds, straight from the canonical catalog the installer and the on-boot reconciler both read. It is the full set a role’s permissionIds can draw from.

ModulePermissionGrants
Dashboardview_dashboardAccess to the main executive overview
User Managementmanage_usersFull administrative rights over users
User Managementview_usersRead-only access to browse users
User Managementmanage_groupsManage organizational groups
User Managementview_groupsRead-only access to view groups
RBACmanage_rolesCreate and modify system roles
RBACview_rolesRead-only access to view roles (prerequisite for manage_roles / manage_permissions)
RBACmanage_permissionsAssign roles and per-user permission overrides
Workflowmanage_workflowsDesign lifecycle workflows (build and submit for approval — not approve)
Workflowapprove_workflowsApprove or reject a workflow design and promote a version live
Workflowexecute_workflowsManually trigger and execute workflows
Workflowmanage_approvalsApprove or reject workflow-driven requests
Auditview_logsRead-only access to the system audit trail
Auditmanage_logsReserved. Audit logs are append-only and cannot be deleted or purged by anyone. Today this only adds audit logs to reports, the same as view_logs
Integrationmanage_hooksFull control of Identity Hooks (superset of connect + policy + writeback)
Integrationmanage_integrationsConnect/configure identity providers (CRUD + test + sync) — no policy edit or writeback
Integrationmanage_alignment_policyEdit the AlignSync source-of-truth policy and source file (does not grant writeback)
Integrationexecute_identity_writebackPush single-user attribute writeback / rollback to a connected directory
Integrationapprove_identity_changesApprove or reject pending AlignSync bulk reconciliations (separation of duties)
Integrationview_saas_discoveryView SaaS Discovery: per-app active users and utilisation, dormant accounts and accounts that match nobody in your directory (read-only)
Securitymanage_securityModify global security policies
Securitycreate_api_tokensCreate personal API tokens for scripted API access (scoped to a subset of your own permissions; revocable; expire within a year)
Securityview_cloud_infrastructureView AWS/Azure cloud infrastructure & cost maps
Compliancemanage_complianceExecute compliance audits
Complianceview_assigned_complianceView only the compliance sections assigned to you (auto-granted on assignment)
Reportingview_reportingAccess to advanced system reporting
Systemview_systemView the System panels: health, software/OS update status, and backup/restore points (read-only; not the reporting hub)
Systemrequest_system_updatesRequest a DB backup, application patch, or host OS patch (requires admin approval to run)
Systemapprove_system_updatesApprove or reject pending backup/patch/OS-update requests (admin-level)
Financeview_financeAccess to Finance Insights
Financemanage_financeFull access to financial reconciliation
Financesubmit_invoiceSubmit an invoice or expense into your own review queue (self-service; does not unlock the Finance workspace or other people’s documents)
Financeapprove_invoiceApprove submitted invoices (separation of duties)
Financepay_invoiceMark approved invoices as paid (separation of duties)
Financeclose_financeLock an accounting period / run month-end close (separation of duties; distinct from approving invoices)
Financemanage_finance_policyEdit finance control policy: the amount-tiered approval rules for invoices and budget transfers, plus exchange rates and base currency (separate from manage_finance so operators cannot weaken their own approval requirements)
Financeview_finance_budgetsView the budgets you own (your department); does not unlock the full Finance workspace
Financemanage_finance_budgetCreate and edit your own department budgets (a manager cannot edit a peer’s budget)
Financesubmit_finance_budgetSubmit your own budget for approval (the submitter cannot approve it)
Financeapprove_finance_budgetApprove or reject a submitted budget and lock it (distinct from approving invoices; cannot approve your own budget)
Financeview_finance_consolidatedView all budgets across every department (bypasses the owner scope)
Financemanage_all_finance_budgetsCreate, edit and lock any budget in any department
Financetransfer_finance_budgetReallocate budget across departments (two-person approval; fully audited)
Organizationview_org_chartView company organizational structure
Organizationmanage_org_chartManage and save organizational snapshots
HRview_referralsAccess to the internal referrals portal
HRmanage_referralsSubmit and track your own employee referrals (same access as view_referrals; there is no screen for other people’s referrals)
HRmanage_recruitmentManage job postings and candidate pipelines
HRview_recruitmentView job postings and candidate pipelines
HRconduct_interviewSubmit interview scorecards
HRapprove_offerApprove and send candidate offers
HRschedule_interviewsManage interview logistics without viewing feedback
HRsource_candidatesAdd candidates to the top of the funnel only
HRreview_executive_packetRead-only access to finalized candidate packets
HRview_employee_recordsView employee files: employment details, job history, personal details and emergency contacts
HRmanage_employee_recordsEdit employee files and record job changes (title, department, manager, level, location)
HRview_compensationView employee compensation history (each view is audit-logged)
HRmanage_compensationAdd compensation records to an employee file
HRview_employee_reportsView people reports: headcount, joiners and leavers, turnover and tenure
HRexport_compensationBuild the payroll hand-off file: joiners, leavers, pay changes and approved leave for a period, with pay amounts
HRmanage_employee_reviewsCreate and launch performance review cycles, reassign reviewers, and read reviews (each read is audit-logged)
HRmanage_employee_trainingKeep the list of training items, assign them to people, and see who has completed them
HRmanage_employee_surveysCreate, open and close anonymous staff surveys and read their combined results (never individual answers)
HRmanage_leaveSet up leave types and holiday calendars, adjust balances, and approve or decline any time-off request
Securitymanage_phishing_simulationCreate, approve and send phishing simulations to your own staff, and see who clicked or reported (each view of per-person results is audit-logged)
Security Labview_security_findingsView security scan findings and reports
Security Labrun_security_scanLaunch security scans and probes
Security Labmanage_security_findingsTriage findings (status, risk acceptance, notes)
Security Labmanage_security_scopesManage scan scopes and target assets
Security Labexport_security_reportExport security findings reports
Devicesview_devicesView the managed Mac fleet and per-machine inventory
Devicesmanage_devicesEnroll and manage devices (issue and revoke enrollment tokens)
Devicesmanage_device_destructiveDestructive or secret device actions: remote wipe, recovery-key reveal, push-certificate key backup (requires re-authentication)
Access Governancerequest_accessSubmit a self-service request for an app, licence or access (routes to an approver)
Access Governanceapprove_access_requestApprove or reject pending access requests (separation of duties; fulfilled only on approval, then at IT’s provisioning gate)
Access Governancecertify_accessMake keep/revoke decisions on access-certification items assigned to you (attestation)
Access Governanceview_access_reviewsView access-certification campaigns and their review items (read-only)
Access Governancemanage_access_reviewsCreate and administer access-certification campaigns (launch, assign reviewers, close, revoke)
User Managementmanage_personasCreate and edit role personas (the hardware/license/access bill-of-materials); complete a draft persona at the IT step
AIuse_aiUse AI assistant features. Required in addition to the relevant feature permission only when “Require explicit AI permission” is enabled in Security Settings

Related reference