Skip to main content

Roles & Permissions

RBAC

Six built-in roles provide granular access control. From super_admin with full access to viewer with read-only permissions.

Role Hierarchy

Roles follow a hierarchy where higher roles inherit all permissions from lower roles. The hierarchy is: super_admin → admin → specialized roles (billing, analytics, developer) → viewer.

super_admin(Super Admin)Owner

Full access to everything. Can delete the organization and transfer ownership.

All permissionsDelete organizationTransfer ownershipManage super_admins
admin(Admin)

Manage members, settings, and most features. Cannot delete organization.

Manage members (except super_admin)Update organization settingsView all analyticsManage integrationsManage API keys
billing(Billing)

Access to billing, invoices, and subscription management only.

View/update billingManage subscriptionsDownload invoicesUpdate payment methods
analytics(Analytics)

View analytics dashboards and export reports. No configuration access.

View analytics dashboardsExport reportsCreate saved views
developer(Developer)

Access to API keys, webhooks, and technical configuration.

View/create API keysConfigure webhooksView logsAccess developer tools
viewer(Viewer)

Read-only access. Can view resources but cannot make changes.

View resourcesView membersView basic analytics

Permission Matrix

Detailed breakdown of what each role can do across different resource types.

Permission
Super Admin
Admin
Billing
Analytics
Developer
Viewer
Organization
Delete organization
Update settings
View details
Members
Invite members
Remove members
Change roles
View members
Billing
Manage subscription
View invoices
Update payment
API
Create API keys
View API keys
Configure webhooks
Analytics
View dashboards
Export reports
Create saved views

Checking Permissions

Use the SDK hooks to check user roles and permissions in your components.

import { useOrganization } from '@sylphx/sdk/react'

function AdminPanel() {
  const { role, isAdmin, isSuperAdmin } = useOrganization()

  // Check exact role
  if (role === 'super_admin') {
    return <SuperAdminDashboard />
  }

  // Check admin-level (super_admin OR admin)
  if (isAdmin) {
    return <AdminDashboard />
  }

  // Check super admin only
  if (isSuperAdmin) {
    return <DangerZone />
  }

  return <AccessDenied />
}

Server-Side Permission Checks

Verify permissions in API routes and server components for security.

// app/api/organization/settings/route.ts
import {
  requireOrganization,
  requirePermission
} from '@sylphx/sdk/nextjs'
import { NextResponse } from 'next/server'

export async function PATCH(request: Request) {
  // Require organization context + specific permission
  const { organization, membership } = await requireOrganization()
  await requirePermission('organization:update')

  const updates = await request.json()

  // Certain updates require super_admin
  if (updates.settings?.allowedDomains !== undefined) {
    if (membership.role !== 'super_admin') {
      return NextResponse.json(
        { error: 'Only super_admin can modify domain settings' },
        { status: 403 }
      )
    }
  }

  // Apply updates
  const updated = await db.organization.update({
    where: { id: organization.id },
    data: updates,
  })

  return NextResponse.json(updated)
}

Always Verify Server-Side

Client-side permission checks are for UX only. Always verify permissions server-side before performing sensitive operations.

Available Permissions

Complete list of permission strings available for checking.

Organization
organization:readorganization:updateorganization:deleteorganization:transfer
Members
members:readmembers:invitemembers:removemembers:update-role
Billing
billing:readbilling:writebilling:invoicesbilling:payment-methods
API Keys
api-keys:readapi-keys:createapi-keys:revoke
Analytics
analytics:readanalytics:exportanalytics:create-views
Security
security:audit-logssecurity:settingssecurity:sso

Changing Roles

Admins can change member roles, with restrictions to prevent privilege escalation.

Update Member Role
import { useOrganization } from '@sylphx/sdk/react'

function MemberRoleEditor({ member }: { member: Membership }) {
  const { updateMemberRole, role: myRole } = useOrganization()
  const [isUpdating, setIsUpdating] = useState(false)

  // Determine which roles current user can assign
  const assignableRoles = useMemo(() => {
    if (myRole === 'super_admin') {
      return ['super_admin', 'admin', 'billing', 'analytics', 'developer', 'viewer']
    }
    if (myRole === 'admin') {
      // Admins can't create super_admins
      return ['admin', 'billing', 'analytics', 'developer', 'viewer']
    }
    return []
  }, [myRole])

  // Can't edit your own role
  const canEdit = member.userId !== currentUserId && assignableRoles.length > 0

  const handleRoleChange = async (newRole: OrganizationRole) => {
    setIsUpdating(true)
    try {
      await updateMemberRole(member.userId, newRole)
      toast.success(`Updated ${member.user.name}'s role to ${newRole}`)
    } catch (error) {
      if (error.code === 'CANNOT_DEMOTE_OWNER') {
        toast.error('Cannot change the organization owner\'s role')
      } else if (error.code === 'INSUFFICIENT_PERMISSIONS') {
        toast.error('You don\'t have permission to assign this role')
      } else {
        toast.error('Failed to update role')
      }
    } finally {
      setIsUpdating(false)
    }
  }

  if (!canEdit) {
    return <span className="text-muted-foreground">{member.role}</span>
  }

  return (
    <Select
      value={member.role}
      onValueChange={handleRoleChange}
      disabled={isUpdating}
    >
      {assignableRoles.map((role) => (
        <SelectItem key={role} value={role}>
          {role}
        </SelectItem>
      ))}
    </Select>
  )
}

Role Assignment Rules

  • • Only super_admin can promote users to super_admin
  • • Users cannot change their own role
  • • The organization owner (first super_admin) cannot be demoted
  • • Admins can assign any role except super_admin

Custom Roles (Enterprise)

Enterprise plans can define custom roles with specific permission sets.

Define Custom Roles
// Configure custom roles in SylphxProvider
<SylphxProvider
  config={{
    organization: {
      roles: {
        // Extend built-in roles
        extend: true,

        // Define custom roles
        custom: [
          {
            name: 'project_manager',
            displayName: 'Project Manager',
            inheritsFrom: 'developer', // Start with developer permissions
            additionalPermissions: [
              'members:invite',
              'analytics:read',
            ],
            removePermissions: [
              'api-keys:create', // Remove API key creation
            ],
          },
          {
            name: 'external_auditor',
            displayName: 'External Auditor',
            inheritsFrom: 'viewer',
            additionalPermissions: [
              'security:audit-logs',
              'analytics:export',
            ],
          },
          {
            name: 'support_agent',
            displayName: 'Support Agent',
            inheritsFrom: null, // Start from scratch
            permissions: [
              'members:read',
              'organization:read',
              'support:tickets:read',
              'support:tickets:write',
            ],
          },
        ],

        // Role hierarchy for inheritance
        hierarchy: [
          'super_admin',
          'admin',
          'project_manager',
          'developer',
          'support_agent',
          'external_auditor',
          'viewer',
        ],
      },
    },
  }}
>
  {children}
</SylphxProvider>