concepts
Roles & Permissions
BurnerByte's dynamic RBAC system with DB-backed roles and permissions.
Overview
BurnerByte uses a two-level, permission-based RBAC system. Every API endpoint checks a specific permission key from the role_permissions table in the database — there are no hardcoded rank checks. Roles and their permissions are stored in the roles, permissions, and role_permissions tables and can be managed via the admin API or Settings → Roles in the UI.
There are 5 default roles in total: 3 org-scoped (owner, admin, member) and 2 team-scoped (lead, member). is_system_admin is a separate boolean flag on the user row — it is not an RBAC role and does not appear in the roles tables (see System Admin below).
Org Roles
| Role | Rank | Description |
|---|---|---|
owner | 3 | Full control over the organization, including deletion |
admin | 2 | Manage members, domains, teams, and settings. Cannot delete the org |
member | 1 | Read-only access to org resources. Access to teams they belong to |
Team Roles
| Role | Rank | Description |
|---|---|---|
lead | 2 | Full control of team settings, members, domain assignments, webhooks, API keys, and inboxes |
member | 1 | Create and manage inboxes, view emails, plus all view permissions |
Permission Keys
Org Permissions
| Key | Description |
|---|---|
org.view | View organization info |
org.settings.view | View organization settings |
org.settings.manage | Edit organization settings |
org.delete | Delete the organization |
org.members.view | View member list |
org.members.invite | Invite new members |
org.members.add | Directly add existing users |
org.members.remove | Deactivate members |
org.members.role | Change member roles |
org.domains.view | View domains list |
org.domains.manage | Create, verify, delete domains |
org.teams.create | Create teams |
org.teams.delete | Delete teams |
org.teams.manage | Archive, restore, view impact |
org.audit.view | View audit logs |
org.audit.export | Export audit logs |
org.analytics.view | View org analytics |
Team Permissions
| Key | Description |
|---|---|
team.view | View team info |
team.settings.manage | Edit team settings |
team.members.view | View team members |
team.members.manage | Add/remove team members |
team.members.role | Change team member roles |
team.domains.view | View domain assignments |
team.domains.manage | Update domain assignment settings |
team.webhooks.view | View webhooks and delivery logs |
team.webhooks.manage | Create/edit/delete webhooks |
team.apikeys.view | View API keys |
team.apikeys.manage | Create/revoke/rotate API keys |
team.inboxes.view | View team inboxes |
team.inboxes.create | Create inboxes |
team.inboxes.manage | Manage inboxes |
team.emails.view | View emails |
team.emails.manage | Mark emails read/unread and delete emails |
team.analytics.view | View team analytics |
Default Role Assignments
Org Roles
| Permission | Owner | Admin | Member |
|---|---|---|---|
org.view | ✅ | ✅ | ✅ |
org.settings.view | ✅ | ✅ | ✅ |
org.settings.manage | ✅ | ✅ | ❌ |
org.delete | ✅ | ❌ | ❌ |
org.members.view | ✅ | ✅ | ✅ |
org.members.invite | ✅ | ✅ | ❌ |
org.members.add | ✅ | ✅ | ❌ |
org.members.remove | ✅ | ✅ | ❌ |
org.members.role | ✅ | ✅ | ❌ |
org.domains.view | ✅ | ✅ | ✅ |
org.domains.manage | ✅ | ✅ | ❌ |
org.teams.create | ✅ | ✅ | ❌ |
org.teams.delete | ✅ | ✅ | ❌ |
org.teams.manage | ✅ | ✅ | ❌ |
org.audit.view | ✅ | ✅ | ❌ |
org.audit.export | ✅ | ✅ | ❌ |
org.analytics.view | ✅ | ✅ | ✅ |
Team Roles
| Permission | Lead | Member |
|---|---|---|
team.view | ✅ | ✅ |
team.settings.manage | ✅ | ❌ |
team.members.view | ✅ | ✅ |
team.members.manage | ✅ | ❌ |
team.members.role | ✅ | ❌ |
team.domains.view | ✅ | ✅ |
team.domains.manage | ✅ | ❌ |
team.webhooks.view | ✅ | ✅ |
team.webhooks.manage | ✅ | ❌ |
team.apikeys.view | ✅ | ✅ |
team.apikeys.manage | ✅ | ❌ |
team.inboxes.view | ✅ | ✅ |
team.inboxes.create | ✅ | ✅ |
team.inboxes.manage | ✅ | ✅ |
team.emails.view | ✅ | ✅ |
team.emails.manage | ✅ | ✅ |
team.analytics.view | ✅ | ✅ |
Enforcement
Every API endpoint checks a specific permission key via the checkOrgPermission or checkTeamPermission helpers. These look up the user's role, then query the in-memory permission cache to verify the role has the required key. No hardcoded rank comparisons are used for permission checks.
Self-Protection
Users cannot modify peers at the same or higher rank. Role change and deactivation endpoints use RequireRankAbove (org scope) or RequireTeamRankAbove (team scope) to enforce this — the acting user's rank must be strictly higher than the target's. System admins bypass the check.
Org-Level Fallback
Org admins and owners (rank ≥ 2) can access any team's resources in their own org without being an explicit team member — the check short-circuits on org rank before the team membership is consulted. RequireTeamPermission first confirms the {teamId} in the route actually belongs to the {orgId}, so an admin cannot pair their own org with another tenant's team.
Permission Cache
Permissions are loaded into an in-memory cache at startup from the role_permissions table. The cache is thread-safe (sync.RWMutex) and is refreshed when a role's permission set changes through the admin API (a create that supplies permissions, or a permission update). A role deletion does not currently trigger a refresh, so a deleted role stays cached until the API restarts.
Custom Roles
Admins can create custom roles with specific permissions via Settings → Roles or the admin API:
POST /api/v1/admin/roles— create a new role with scope, value, label, description, rank, and permissionsPATCH /api/v1/admin/roles/{roleId}— update label, description, or permissionsDELETE /api/v1/admin/roles/{roleId}— remove a custom role
Custom roles appear in the permission cache alongside system roles. Note that org_memberships.role and team_memberships.role still carry CHECK constraints limiting stored values to owner/admin/member and lead/member, so a custom role cannot yet be assigned to a member — custom roles currently only adjust the permission sets attached to the built-in role values.
System Admin
The is_system_admin flag on the user record bypasses all RBAC checks and grants access to all /api/v1/admin routes, including:
- System stats and health checks
- User management (list, edit, delete platform users)
- Platform settings (registration, email verification, password policy, lockout)
- SSO provider management
- Role and permission management
This flag is set during the initial setup wizard for the platform owner.
Operating Without an Organization
System admins are exempt from the forced onboarding redirect. A system admin with no organization can still access the platform-level surfaces — Settings → Roles, Settings → SSO, Settings → System, and the platform audit log — without creating or joining an org. Org-scoped tabs (General, Users) and org-scoped nav items (domains, teams, analytics) appear only once an org exists.
Encryption at Rest
Sensitive configuration values (SSO client secrets, SMTP passwords) are encrypted with AES-256-GCM before storage in the system_configs table. To enable, set encryption.key to a 64-character hex string (32 bytes). Generate with:
openssl rand -hex 32