Skip to main content
Version: v0.1.8

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:

  1. Seat Types (Licensing Axis): Defines the user's licensing tier and default capabilities.
  2. 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_dn column, 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:

  1. Superadmin: Bypasses all checks.
  2. Admin Seat: Bypasses all checks for the organization.
  3. Implicit Grants: Grants based on the user's seat type (e.g., Builders implicitly get project.edit).
  4. Group Grants: Explicit rows in group_permissions matching 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 seeded role (default viewer) 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 asserts is_superadmin = FALSE across every SSO insert path.)
  • Only a superadmin can grant it. PATCH /api/users/{id} accepts an is_superadmin field, but writes to it are gated behind caller.is_superadmin — holding org.admin is 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
  • <ProtectedRoute> Component: A wrapper component used in route definitions to prevent unauthorized access to entire pages.
    • Source: paas/frontend/src/components/ProtectedRoute.tsx

The frontend fetches the user's flat permission list from the /api/groups/me/permissions endpoint (see paas/backend/routers/groups.py).