RBAC and Portal Permissions
RBAC and Portal Permissions
Section titled “RBAC and Portal Permissions”The Arbitex Cloud Portal uses role-based access control (RBAC) to govern what each organization member can see and do. Every member is assigned exactly one role that determines their access across DLP rules, audit logs, billing, outpost management, and organization settings.
This guide covers the five portal roles, the permission matrix, how to invite and manage members, how permissions are enforced in the backend, and common role patterns for different team structures.
Overview
Section titled “Overview”The Cloud Portal defines five roles through the OrgRole enum:
| Role | Purpose |
|---|---|
org_admin |
Full access — manage members, configure DLP, view billing, manage outposts |
dlp_viewer |
Read-only access to DLP rules and scan results |
audit_viewer |
Read-only access to audit logs and events |
billing_viewer |
Read-only access to billing, invoices, and usage data |
outpost_viewer |
Read-only access to outpost status and configuration |
Every organization starts with at least one org_admin. Additional members are invited with a specific role and can be reassigned later by any org_admin.
Role reference table
Section titled “Role reference table”The following matrix shows the access level each role has across portal feature areas. Cells indicate Read (view data), Write (create, update, delete), or None (no access).
| Role | DLP Rules | Audit Log | Billing | Outpost Mgmt | Members | Settings |
|---|---|---|---|---|---|---|
org_admin |
Read / Write | Read | Read | Read / Write | Read / Write | Read / Write |
dlp_viewer |
Read | None | None | None | None | None |
audit_viewer |
None | Read | None | None | None | None |
billing_viewer |
None | None | Read | None | None | None |
outpost_viewer |
None | None | None | Read | None | None |
What each access level means
Section titled “What each access level means”DLP Rules — Read / Write (org_admin):
- View all DLP rules, scan results, and detection events
- Create, update, enable/disable, and delete DLP rules
- Configure DLP detection thresholds and action policies
DLP Rules — Read (dlp_viewer):
- View all DLP rules and their configurations
- View scan results and detection events
- Cannot create, modify, or delete rules
Audit Log — Read (org_admin, audit_viewer):
- View audit events with all filters (action, user, severity, date range)
- Export audit events as CSV or JSON
- View event details including IP address and user agent
Billing — Read (org_admin, billing_viewer):
- View current plan, seat count, and usage summary
- View invoice history and payment method (masked)
- View usage breakdown by model and provider
- Export usage data
Outpost Mgmt — Read / Write (org_admin):
- View outpost status, configuration, and health
- Run outpost actions (test connection, clear cache)
- Update outpost configuration
Outpost Mgmt — Read (outpost_viewer):
- View outpost status and configuration
- View outpost health and sync status
- Cannot run actions or modify configuration
Members — Read / Write (org_admin):
- View all organization members and their roles
- Invite new members with a specific role
- Update existing member roles
- Remove members from the organization
Settings — Read / Write (org_admin):
- View and modify organization settings
- Configure SSO, API keys, and security policies
- Manage organization-level preferences
Inviting members
Section titled “Inviting members”Organization admins invite new members via the portal Team page or the Members API.
Portal UI
Section titled “Portal UI”- Navigate to Settings → Team
- Click Invite Member
- Enter the email address
- Select a role from the dropdown (defaults to
org_admin) - Click Send Invite
The invited user receives an email with a one-time invite link. The invite token is displayed once and not stored — if the email is lost, the admin must remove the pending member and re-invite.
API: invite a member
Section titled “API: invite a member”POST /v1/orgs/{org_id}/members/inviteAuthorization: Bearer <org_jwt>Content-Type: application/json
{ "role": "dlp_viewer"}Request body — InviteRequest:
| Field | Type | Required | Description |
|---|---|---|---|
email |
string | Yes | Email address of the user to invite |
role |
OrgRole enum |
No | Role to assign. Default: org_admin |
OrgRole enum values: org_admin, dlp_viewer, audit_viewer, billing_viewer, outpost_viewer
Response (201 Created):
{ "member": { "user_id": "m-8f3a2b1c-...", "role": "dlp_viewer", "created_at": "2026-03-15T10:00:00Z", "last_login_at": null }, "invite_token": "inv_dGhpcyBpcyBhIHNhbXBsZSB0b2tlbg..."}The invite_token is a one-time token prefixed with inv_ followed by 32 URL-safe base64 characters. It is generated from secrets.token_bytes(24) and displayed only once in the API response. The token is not stored in the database — if it is lost, remove the member and re-invite.
Bulk invite
Section titled “Bulk invite”For onboarding multiple team members at once:
POST /v1/orgs/{org_id}/members/bulk-inviteAuthorization: Bearer <org_jwt>Content-Type: application/json
{ "invites": [ ]}Constraints:
- Maximum 50 invites per request
- Duplicate emails within the org are silently skipped (counted in
skipped)
Response (200 OK):
{ "invited": 3, "skipped": 1, "errors": 0}Role assignment
Section titled “Role assignment”Updating an existing member’s role
Section titled “Updating an existing member’s role”Organization admins can change any member’s role via the portal or API.
Portal: Navigate to Settings → Team, click the role dropdown next to a member, and select the new role.
API:
PATCH /v1/orgs/{org_id}/members/{member_id}/roleAuthorization: Bearer <org_jwt>Content-Type: application/json
{ "role": "audit_viewer"}Request body — RoleUpdateRequest:
| Field | Type | Required | Description |
|---|---|---|---|
role |
OrgRole enum |
Yes | New role to assign |
Response (200 OK):
{ "user_id": "m-8f3a2b1c-...", "role": "audit_viewer", "created_at": "2026-03-15T10:00:00Z", "last_login_at": "2026-03-15T14:30:00Z"}Role changes take effect immediately. The member’s next API call or page load will use the new role. Existing SSO sessions are re-evaluated on the next token refresh.
Removing a member
Section titled “Removing a member”DELETE /v1/orgs/{org_id}/members/{member_id}Authorization: Bearer <org_jwt>Response: 204 No Content
Constraints:
- Cannot remove yourself
- Cannot remove the last
org_admin— the organization must always have at least one admin
Permission enforcement
Section titled “Permission enforcement”The Cloud Portal backend enforces permissions using the require_role() dependency. This function is injected into FastAPI route handlers as a dependency and checks the authenticated user’s role against a list of allowed roles before the handler executes.
How require_role() works
Section titled “How require_role() works”1. Client sends request with Bearer JWT2. JWT is decoded → extracts org_id and user_id3. User's role is loaded from the org_admins table4. require_role(allowed_roles) checks: - Is the user's role in the allowed_roles set? - If yes → request proceeds to the handler - If no → 403 Forbidden responseToken role claim flow:
SSO Login → Look up user in org_admins table → Read role column (org_admin / dlp_viewer / audit_viewer / ...) → Embed role in SSO session JWT as "role" claim → Frontend uses role claim for UI gating → Backend re-validates role on every API call via require_role()Example: protecting a DLP endpoint
Section titled “Example: protecting a DLP endpoint”@router.get("/v1/orgs/{org_id}/dlp/rules")async def list_dlp_rules( org_id: str, org_ctx: OrgContext = Depends(get_org_context), _role: str = Depends(require_role(["org_admin", "dlp_viewer"])),): # Only org_admin and dlp_viewer can reach this handler ...Example: admin-only endpoint
Section titled “Example: admin-only endpoint”@router.post("/v1/orgs/{org_id}/members/invite")async def invite_member( org_id: str, body: InviteRequest, org_ctx: OrgContext = Depends(get_org_context), _role: str = Depends(require_role(["org_admin"])),): # Only org_admin can invite new members ...IDOR protection
Section titled “IDOR protection”In addition to role checks, every org-scoped endpoint enforces tenant isolation:
if org_ctx.org_id != org_id: raise HTTPException(status_code=403, detail="Forbidden: org_id mismatch")This prevents a user from one organization from accessing resources in another organization, even if they have the correct role. The org_id in the JWT must match the org_id in the URL path.
Error responses
Section titled “Error responses”| Status | Condition |
|---|---|
401 Unauthorized |
Missing or invalid JWT |
403 Forbidden |
Valid JWT but role not in allowed_roles, or org_id mismatch |
404 Not Found |
Resource does not exist within the authenticated org |
Common patterns
Section titled “Common patterns”Read-only analyst
Section titled “Read-only analyst”A security analyst who needs to review DLP detections and audit trails but should not modify any rules or settings.
Roles: dlp_viewer + audit_viewer
Since each member can have only one role, assign audit_viewer and grant DLP access separately, or create a combined viewer role if your organization’s workflow requires it. In practice, the recommended approach is:
POST /v1/orgs/{org_id}/members/invite{ "role": "audit_viewer"}The analyst can view audit events and export them for analysis. For DLP visibility, the dlp_viewer role provides read access to DLP rules and scan results.
Compliance auditor
Section titled “Compliance auditor”An external or internal auditor who needs access to audit logs and billing data for compliance reviews.
Recommended role: audit_viewer
The audit viewer role provides read access to all audit events, including filtering by action, user, severity, and date range. Combined with the audit export API, auditors can pull evidence for HIPAA, PCI-DSS, SOC 2, and other frameworks.
For auditors who also need billing visibility (e.g., for cost attestation in SOC 2 reports), assign billing_viewer instead and provide audit log exports via the API.
Outpost operations
Section titled “Outpost operations”An infrastructure team member who monitors outpost health and connectivity.
Recommended role: outpost_viewer
The outpost viewer can see:
- Outpost connection status and last heartbeat
- Configuration (read-only)
- Sync status and certificate expiry
- Health check results
They cannot run actions (test connection, clear cache) or modify outpost configuration — those operations require org_admin.
Team lead with full access
Section titled “Team lead with full access”Role: org_admin
Organization admins have unrestricted access to all portal features. Use this role for:
- Team leads who manage member access
- Security administrators who configure DLP rules
- Platform administrators who manage outpost infrastructure
- Billing administrators who need full visibility
Admin elevation
Section titled “Admin elevation”The org_admin role is the most privileged role in the Cloud Portal. Only organization admins can:
- Manage members: invite, update roles, remove members
- Manage roles: assign or change any member’s role
- Configure DLP: create, update, enable/disable, and delete DLP rules
- Manage outposts: run actions, update configuration
- Modify settings: update organization preferences, SSO configuration, API keys
- Access billing: view and manage billing, invoices, and payment methods
Elevation rules
Section titled “Elevation rules”- Only
org_admincan assign roles. No other role can invite members or change role assignments. - Cannot remove the last admin. The API prevents removing or demoting the last
org_adminto ensure the organization always has at least one admin. - Cannot remove yourself. Members cannot remove their own membership — another admin must do it.
- Role changes are immediate. When an admin changes a member’s role, the new role takes effect on the member’s next API call or page load.
Self-serve signup
Section titled “Self-serve signup”When a user signs up for Arbitex through the self-serve flow, they are automatically assigned the org_admin role as the founding member of their organization. This ensures they have full access to configure DLP, invite team members, and set up outposts.
Migration note
Section titled “Migration note”When the RBAC system is enabled for an existing organization, all current members receive the org_admin role by default. This ensures no disruption to existing workflows — all members retain their current access levels.
After migration, organization admins should review the member list and assign appropriate roles:
- Navigate to Settings → Team
- Review each member’s current role (all will show
org_admin) - Click the role dropdown and select the appropriate role for each member
- Members who only need read access to specific areas should be downgraded to the appropriate viewer role
Recommended migration checklist
Section titled “Recommended migration checklist”| Step | Action |
|---|---|
| 1 | Identify who needs full admin access (typically 1–3 people) |
| 2 | Keep those members as org_admin |
| 3 | Assign dlp_viewer to security analysts |
| 4 | Assign audit_viewer to compliance team members |
| 5 | Assign billing_viewer to finance team members |
| 6 | Assign outpost_viewer to infrastructure/ops team members |
| 7 | Verify each member can access what they need (and nothing more) |
See also
Section titled “See also”- API key security — API key creation and rotation (org_admin only)
- Audit log export — Exporting audit events for compliance
- API reference — batch 31 — Full RBAC Members API reference
- SSO configuration — Single sign-on setup (org_admin only)