Roles & Permissions
Learn how role-based access control (RBAC) works in the SaaS Boilerplate, including membership roles, permission validation, and organization-scoped access control.
By the end of this guide, you'll understand how the SaaS Boilerplate implements role-based access control, how membership roles determine user permissions within organizations, and how to enforce proper access control in your features.
Before You Begin
- Basic Knowledge: Understanding of authentication concepts and multi-tenant architecture
- Prerequisites: Familiarity with the Authentication & Sessions and Organizations & Tenancy concepts
- Environment: A running SaaS Boilerplate instance with user authentication configured
Core Concepts
The SaaS Boilerplate implements a comprehensive role-based access control (RBAC) system that ensures users can only perform actions appropriate to their organizational role and responsibilities.
Role Hierarchy
The system defines three distinct membership roles that form a clear hierarchy of permissions:
- Owner: Full administrative control over the organization, including billing management, member administration, and organization deletion
- Admin: Elevated permissions for managing organization settings, members, and most business operations, but cannot delete the organization or perform certain owner-only actions
- Member: Basic access to organization resources and standard business operations, with read/write access to most features but limited administrative capabilities
Membership-Based Permissions
Unlike user-level permissions, roles are organization-specific and stored in membership records:
- Organization-Scoped: Each user can have different roles in different organizations
- Dynamic Assignment: Roles can be changed by organization owners and admins
- Inheritance Model: Higher-level roles (owner, admin) include all permissions of lower-level roles (member)
- Membership Management: Users can be added, removed, or have their roles modified within organizations
Permission Validation
The system enforces permissions through multiple layers:
- Session-Level Validation: Role requirements checked during authentication
- Endpoint-Level Guards: Controllers validate user roles before executing business logic
- Business Rule Enforcement: Procedures implement role-specific business rules
- Data Isolation: All queries automatically scope to the user's organization and respect role limitations
Data Models
The role system is built around membership entities that link users to organizations with specific permissions.
Prop
Type
Implementation Details
Role-based access control is implemented through a layered architecture that provides both low-level validation and high-level business rule enforcement.
Define Role Requirements
Controllers specify required roles using the authentication context, ensuring only authorized users can access protected endpoints.
getSession: async <
TRequirements extends AuthRequirements | undefined = undefined,
TRoles extends OrganizationMembershipRole[] | undefined = undefined,
>(
options?: GetSessionInput<TRequirements, TRoles>,
): Promise<AppSession<TRequirements, TRoles>> => {
// Complex session retrieval with role validation logic
// Validates user authentication and organization membership roles
}Implement Role Validation
The authentication procedure validates that users have the required roles within their active organization before allowing access.
if (options?.roles && options.roles.length > 0 && session) {
if (!organization || !membership) {
throw new Error('NO_ORGANIZATION_ACCESS')
}
if (!options.roles.includes(membership.role as OrganizationMembershipRole)) {
throw new Error('INSUFFICIENT_PERMISSIONS')
}
}Apply Role Guards in Controllers
Business logic controllers use role validation to protect sensitive operations and ensure proper access control.
const session = await context.auth.getSession({
requirements: 'authenticated',
roles: ['owner', 'admin'], // Only owners and admins can modify memberships
})Enforce Business Rules
Procedures implement role-specific business rules, such as preventing deletion of organization owners.
if (membership.role === 'owner')
throw new Error('Cannot delete organization owner')Practical Examples
Let's see how role-based permissions work in real business scenarios within the SaaS Boilerplate.
Membership Management with Role Validation
The membership system demonstrates how roles control administrative access to organization member management.
update: igniter.mutation({
name: 'updateMembership',
description: 'Update member role',
method: 'PUT',
path: '/:id' as const,
use: [MembershipFeatureProcedure(), AuthFeatureProcedure()],
body: z.object({
userId: z.string().optional(),
role: z.string().optional(),
}),
handler: async ({ request, response, context }) => {
// Only owners and admins can modify member roles
const session = await context.auth.getSession({
requirements: 'authenticated',
roles: ['owner', 'admin'],
})
const { id } = request.params
const { userId, role } = request.body
const result = await context.membership.update({
id,
userId,
role,
organizationId: session.organization.id,
})
return response.success(result)
},
}),API Key Management with Elevated Permissions
API key creation requires higher-level permissions since these keys provide programmatic access to organization resources.
const session = await context.auth.getSession({
requirements: 'authenticated',
roles: ['owner', 'admin'], // API key management requires elevated permissions
})Organization Statistics with Member Access
Basic organization statistics are available to all members, demonstrating read access for lower-level roles.
const sessionWithRoles = await context.auth.getSession({
requirements: 'authenticated',
roles: ['admin', 'member', 'owner'], // All organization members can view stats
})Troubleshooting
Best Practices
Authentication & Sessions
Learn how the SaaS Boilerplate handles user authentication, session management, and organization-based access control using Better Auth.
Controllers & Procedures
Learn how to design typed APIs with Igniter controllers, implement rigorous validation with Zod, and generate comprehensive OpenAPI documentation.