Permissions API Reference
Available resources, actions, and permission checking APIs.
The RBAC system uses a two-tier permission model:
- Hierarchy-based permissions - Role levels determine which roles can manage other roles
- Feature-specific permissions - Resource/action pairs grant access to specific features
Configuration
All RBAC settings are configured in packages/rbac/src/rbac.config.ts using defineRBACConfig:
import { defineRBACConfig } from './core/factory';export default defineRBACConfig({ resources: { PROJECT: 'project' }, actions: { ARCHIVE: 'archive' }, roles: { moderator: 30 }, accessController: { project: ['create', 'read', 'update', 'delete', 'archive'], }, permissions: { owner: { project: ['create', 'read', 'update', 'delete', 'archive'] }, admin: { project: ['create', 'read', 'update'] }, member: { project: ['read'] }, },});Type Definitions
Role
A typed union of role names from the role hierarchy.
import { type Role } from '@kit/rbac';// Role = 'owner' | 'admin' | 'member' (plus any custom roles)function setRole(role: Role) { // TypeScript provides autocomplete}DefaultRole
Alias for Role type, kept for backward compatibility.
import { type DefaultRole } from '@kit/rbac';// DefaultRole = Role = 'owner' | 'admin' | 'member'Resources
Resources represent entities that can be protected by permissions. Default resources are included automatically; add custom resources in rbac.config.ts.
import { RESOURCES } from '@kit/rbac';// Default resources (always available)const RESOURCES = { ORGANIZATION: 'organization', MEMBER: 'member', INVITATION: 'invitation', BILLING: 'billing', AC: 'ac', // Access Control // Custom resources from rbac.config.ts are merged here} as const;| Resource | Description |
|---|---|
organization | Organization settings and deletion |
member | Member management |
invitation | Member invitations |
billing | Subscription and payment management |
ac | Access control configuration |
To add custom resources, edit packages/rbac/src/rbac.config.ts:
export default defineRBACConfig({ resources: { PROJECT: 'project', TASK: 'task', },});Actions
Actions represent operations that can be performed on resources. Default actions are included automatically; add custom actions in rbac.config.ts.
import { ACTIONS } from '@kit/rbac';// Default actions (always available)const ACTIONS = { CREATE: 'create', READ: 'read', UPDATE: 'update', DELETE: 'delete', CANCEL: 'cancel', // Custom actions from rbac.config.ts are merged here} as const;To add custom actions, edit packages/rbac/src/rbac.config.ts:
export default defineRBACConfig({ actions: { ARCHIVE: 'archive', PUBLISH: 'publish', EXPORT: 'export', },});Role Hierarchy
Roles are assigned numeric hierarchy levels. Higher values indicate more permissions.
import { ROLE_HIERARCHY } from '@kit/rbac';// Default roles (always available)const ROLE_HIERARCHY = { owner: 100, // Can manage all roles admin: 50, // Can manage members member: 10, // Cannot manage anyone // Custom roles from rbac.config.ts are merged here} as const;The hierarchy determines which roles can manage other roles. A role can only manage roles with a lower hierarchy level.
To add custom roles, edit packages/rbac/src/rbac.config.ts:
export default defineRBACConfig({ roles: { moderator: 30, // Between admin (50) and member (10) viewer: 5, // Below member },});Role Permissions
Role permissions map each role to its allowed resource/action combinations.
import { DEFAULT_ROLE_PERMISSIONS } from '@kit/rbac';// Structure: role -> resource -> actions[]const DEFAULT_ROLE_PERMISSIONS = { owner: { organization: ['update', 'delete'], member: ['create', 'update', 'delete'], invitation: ['create', 'cancel'], ac: ['create', 'read', 'update', 'delete'], billing: ['read', 'update', 'delete'], }, admin: { organization: ['update'], member: ['create', 'update', 'delete'], invitation: ['create', 'cancel'], ac: ['read'], billing: ['read', 'update', 'delete'], }, member: { organization: [], member: [], invitation: ['create'], ac: [], billing: ['read'], },} as const;Permission Functions
canTargetRole
Checks if one role can manage another based on hierarchy levels.
import { canTargetRole } from '@kit/rbac';// Admin (50) can target member (10)canTargetRole('admin', 'member');// Returns: true// Admin (50) cannot target admin (50) by defaultcanTargetRole('admin', 'admin');// Returns: false// With allowEqual, same-level targeting is permittedcanTargetRole('admin', 'admin', true);// Returns: true// With custom role hierarchy (for Dynamic Access Control)const customHierarchy = { supervisor: 40 };canTargetRole('admin', 'supervisor', false, customHierarchy);// Returns: trueThe allowEqual parameter controls whether a role can target roles at the same hierarchy level. This is useful for invitations where an admin should be able to invite other admins.
getRoleHierarchy
Gets the numeric hierarchy level for a role.
import { getRoleHierarchy } from '@kit/rbac';getRoleHierarchy('owner'); // Returns: 100getRoleHierarchy('admin'); // Returns: 50getRoleHierarchy('member'); // Returns: 10// With custom role hierarchyconst customHierarchy = { supervisor: 40 };getRoleHierarchy('supervisor', customHierarchy); // Returns: 40Utility Functions
Additional helpers for working with roles.
import { getCreatorRole, getDefaultRole, getRolesSortedByHierarchy, getAllDefaultRoles,} from '@kit/rbac';// Get the highest-level role (organization creator)getCreatorRole();// Returns: 'owner'// Get the lowest-level role (default for new members)getDefaultRole();// Returns: 'member'// Get roles sorted by hierarchy (highest first)getRolesSortedByHierarchy();// Returns: ['owner', 'admin', 'member']// Get all role namesgetAllDefaultRoles();// Returns: ['owner', 'admin', 'member']All these functions accept an optional customRoleHierarchy parameter for Dynamic Access Control scenarios:
const customHierarchy = { supervisor: 40 };getRolesSortedByHierarchy(customHierarchy);// Returns: ['owner', 'admin', 'supervisor', 'member']Server-side Permission Checking
Using canTargetRole for Member Management
For checking if a user can manage another member:
import { canTargetRole } from '@kit/rbac';// In a server action or API routeconst canManage = canTargetRole( currentUserRole, // Role of the user performing the action targetMemberRole, // Role of the member being managed false, // Don't allow same-level targeting customRoleHierarchy, // Optional: for Dynamic Access Control);if (!canManage) { throw new Error('Cannot manage members with equal or higher roles');}Using Better Auth's Permission API
For checking resource/action permissions:
import { auth } from '@kit/better-auth';import { headers } from 'next/headers';const { success } = await auth.api.hasPermission({ headers: await headers(), body: { permissions: { billing: ['update'], }, },});if (!success) { throw new Error('Permission denied');}The permissions object maps resources to an array of required actions. The check passes if the user has all specified permissions.
Server Action Authorization Middleware
Middleware functions for declarative authorization in server actions using the .use() pattern.
withMinRole
Checks minimum role level using the hierarchy.
import { authenticatedActionClient, withMinRole } from '@kit/action-middleware';export const deleteOrgAction = authenticatedActionClient .use(withMinRole('owner')) .inputSchema(DeleteOrgSchema) .action(async ({ parsedInput, ctx }) => { // Only owners can reach here // ctx.organizationId and ctx.role are available });withFeaturePermission
Checks permissions using Better Auth's permission system.
import { authenticatedActionClient, withFeaturePermission } from '@kit/action-middleware';export const manageBillingAction = authenticatedActionClient .use(withFeaturePermission({ billing: ['update'] })) .inputSchema(BillingSchema) .action(async ({ parsedInput, ctx }) => { // Only users with billing:update permission can reach here });organizationActionClient
Pre-configured client with organization context (no permission checks).
import { organizationActionClient } from '@kit/action-middleware';export const listMembersAction = organizationActionClient .inputSchema(ListMembersSchema) .action(async ({ parsedInput, ctx }) => { const { organizationId, role } = ctx; // List members for the organization });UI Permission Checks
For UI components, use canTargetRole directly from @kit/rbac:
'use client';import { canTargetRole } from '@kit/rbac';function MemberActions({ currentUserRole, targetMemberRole, roleConfig,}) { // Check if current user can manage this member const canManage = canTargetRole( currentUserRole, targetMemberRole, false, roleConfig.roleHierarchy, // Custom role hierarchy if using DAC ); if (!canManage) { return null; } return <EditMemberButton />;}Capability Matrix
Default permission assignments for built-in roles:
| Resource:Action | owner | admin | member |
|---|---|---|---|
| organization:update | Yes | Yes | No |
| organization:delete | Yes | No | No |
| member:create | Yes | Yes | No |
| member:update | Yes | Yes | No |
| member:delete | Yes | Yes | No |
| invitation:create | Yes | Yes | Limited* |
| invitation:cancel | Yes | Yes | No |
| billing:read | Yes | Yes | Yes |
| billing:update | Yes | Yes | No |
| billing:delete | Yes | Yes | No |
| ac:create/update/delete | Yes | No | No |
| ac:read | Yes | Yes | No |
*Members can create invitations but cannot invite higher roles (enforced via canTargetRole).
Access Controller
The ac object is the Better Auth access controller, built from rbac.config.ts:
import { ac, buildAccessController } from '@kit/rbac/access-controller';// Use the pre-built instanceac.newRole({ project: ['read', 'update'] });// Or build a fresh instanceconst customAc = buildAccessController();The access controller is automatically synchronized with your rbac.config.ts settings. When you add custom resources, actions, or permissions, they are immediately available in Better Auth's authorization system.