Permissions API Reference
Available resources, functions, 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/function 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' }, functions: { 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', },});Functions
Functions represent operations that can be performed on resources. Default functions are included automatically; add custom functions in rbac.config.ts.
import { ACTIONS } from '@kit/rbac';// Default functions (always available)const ACTIONS = { CREATE: 'create', READ: 'read', UPDATE: 'update', DELETE: 'delete', CANCEL: 'cancel', // Custom functions from rbac.config.ts are merged here} as const;To add custom functions, edit packages/rbac/src/rbac.config.ts:
export default defineRBACConfig({ functions: { 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/function combinations.
import { DEFAULT_ROLE_PERMISSIONS } from '@kit/rbac';// Structure: role -> resource -> functions[]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', 'cancel'], ac: ['read'], 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 function or API routeconst canManage = canTargetRole( currentUserRole, // Role of the user performing the function 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/function permissions:
import { auth } from '@kit/better-auth';import { getRequestHeaders } from '@tanstack/react-start/server';const { success } = await auth.api.hasPermission({ headers: getRequestHeaders(), body: { permissions: { billing: ['update'], }, },});if (!success) { throw new Error('Permission denied');}The permissions object maps resources to an array of required functions. The check passes if the user has all specified permissions.
Server Function Authorization Middleware
Middleware for declarative authorization in server functions. Layer it onto an function middleware with the native .middleware([...]) step, then continue with .validator(schema) and .handler(...).
withMinRole
Checks minimum role level using the hierarchy.
import { authFunctionMiddleware } from '@kit/function-middleware/functions';import { withMinRole } from '@kit/function-middleware/server';export const deleteOrgFunction = createServerFn({ method: 'POST' }).middleware(authFunctionMiddleware) .middleware([withMinRole('owner')]) .validator(DeleteOrgSchema) .handler(async ({ data, context }) => { // Only owners can reach here // context.organizationId and context.role are available });withFeaturePermission
Checks permissions using Better Auth's permission system.
import { authFunctionMiddleware } from '@kit/function-middleware/functions';import { withFeaturePermission } from '@kit/function-middleware/server';export const manageBillingFunction = createServerFn({ method: 'POST' }).middleware(authFunctionMiddleware) .middleware([withFeaturePermission({ billing: ['update'] })]) .validator(BillingSchema) .handler(async ({ data, context }) => { // Only users with billing:update permission can reach here });organizationFunctionMiddleware
Pre-composed tuple with organization context (no extra permission checks).
import { createServerFn } from '@tanstack/react-start';import { organizationFunctionMiddleware } from '@kit/function-middleware/functions';export const listMembersFunction = createServerFn({ method: 'POST' }).middleware(organizationFunctionMiddleware) .validator(ListMembersSchema) .handler(async ({ data, context }) => { const { organizationId, role } = context; // List members for the organization });UI Permission Checks
For UI components, use canTargetRole directly from @kit/rbac:
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:Function | 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 | Yes |
| 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 | Yes |
*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, functions, or permissions, they are immediately available in Better Auth's authorization system.
This permissions system is part of the TanStack Start Prisma SaaS Kit.