Users and Groups (RBAC Model)
Honeyframe uses a two-axis Role-Based Access Control (RBAC) model that decouples licensing from security permissions.
The Two-Axis Model
Security in Honeyframe is structured around two independent axes:
- Seat Types (Licensing Axis): Defines the user's licensing tier and default capabilities.
- Group Permissions (Security Axis): Defines specific access to resources (projects, datasets, dashboards) via group membership.
Seat Types
Seat types are assigned at the user level and represent their primary role within the platform. They drive implicit organization-wide permissions.
- Admin: Platform administrators with full access to organization settings, users, and all resources.
- Builder: Users who can create and manage project assets, flows, and metadata.
- Analyst: Users focused on data exploration and dashboarding. Can view projects and interact with data.
- Viewer: Read-only users who consume dashboards and project overviews.
The seat type is stored in the seat_type column of the users table. Implicit grants for each seat type are defined in paas/backend/services/permissions.py.
Groups and Permissions
Permissions are never granted directly to users; instead, they are granted to groups. Users inherit permissions by being members of one or more groups.
Groups
Groups are defined in the hubstudio.groups table. A group can be:
- Local: Managed entirely within the Honeyframe platform.
- LDAP-Mapped: Mapped to an external directory via the
ldap_dncolumn, allowing membership to be synchronized with enterprise identity providers.
Permissions
The hubstudio.group_permissions table maps groups to specific capabilities. A permission grant consists of:
- Permission Type: A dot-separated string defining the resource and action (e.g.,
project.edit,dashboard.view). - Target ID: (Optional) Scopes the permission to a specific object (e.g., a specific
dashboard_id). If the Target ID is NULL, the permission is granted organization-wide.
Resolution Logic
The single source of truth for all permission checks is user_has_permission() in paas/backend/services/permissions.py. The resolution follows this precedence:
- Superadmin: Bypasses all checks.
- Admin Seat: Bypasses all checks for the organization.
- Implicit Grants: Grants based on the user's seat type (e.g., Builders implicitly get
project.edit). - Group Grants: Explicit rows in
group_permissionsmatching the user's group memberships.
Superadmin (global privilege)
is_superadmin is a global flag — it bypasses every org-scoped check, across all organizations — and is distinct from the org-scoped admin role/seat. Because granting it is a full privilege escalation, it is governed by stricter rules than ordinary role changes (v0.0.89):
- SSO sign-up never grants it. All four SSO auto-create paths (Google, Microsoft, generic OIDC, SAML) insert new users with
is_superadmin = FALSE; the seededrole(defaultviewer) is the only privilege a first-time SSO sign-in receives. (A prior defect auto-granted superadmin on first SSO sign-in; this was fixed and is now guarded by a static test that assertsis_superadmin = FALSEacross every SSO insert path.) - Only a superadmin can grant it.
PATCH /api/users/{id}accepts anis_superadminfield, but writes to it are gated behindcaller.is_superadmin— holdingorg.adminis not sufficient. In the UI the Make SA / Revoke SA action is visible only to superadmins and hidden on the caller's own row. - Self-revoke is blocked. A superadmin cannot remove their own
is_superadmin, mirroring the self-deactivate guard so the last superadmin can't lock the platform out.
Frontend Implementation
The frontend provides utilities for declarative and programmatic permission gates.
usePermission()Hook: A React hook for checking permissions within components to show/hide UI elements.- Source:
paas/frontend/src/hooks/usePermission.ts
- Source:
<ProtectedRoute>Component: A wrapper component used in route definitions to prevent unauthorized access to entire pages.- Source:
paas/frontend/src/components/ProtectedRoute.tsx
- Source:
The frontend fetches the user's flat permission list from the /api/groups/me/permissions endpoint (see paas/backend/routers/groups.py).