When to Use Each Approach
Before diving into implementation details, here’s a quick guide to help you choose the right approach:Approach 1: Relations as Roles
The simplest way to implement roles is to use directly assignable relations. They work well for roles that always exist and can be defined at development-time. Adding relations is straightforward, and you do not need to add roles very frequently. If roles are static, this is always the preferred approach.Example: Organization Admin Role
In the model below, we define anadmin role at the organization level. Admins can edit billing details and create projects.
Adding Users to Roles
To add users to the admin role, create a tuple like:Extending with Additional Roles
If later you need to add aproject_admin role with permissions to view/edit projects, the model evolves to:
Pros and Cons
✅ Advantages:- Simple to implement and understand
- Fast evaluation performance
- Clear authorization policies
- No additional tuples needed when adding permissions
- Role permissions are straightforward to change, regardless of scale
- Roles must be predefined in the model
- Not suitable for user-defined roles
Approach 2: Simple User-Defined Roles
Many applications require the flexibility for end-users to define their own custom roles, in addition to any pre-defined roles. This approach enables organizations to tailor permissions to their specific needs.Example: Custom Project Admin Role
With the following model, your application can support both static roles and user-defined roles:Setting Up Custom Roles
- Define role permissions by creating tuples that grant the role-specific permissions:
- Assign users to the role:
Adding New Permissions
When you add new permissions to your model, existing roles don’t automatically receive them: To grant the new permission to existing roles, create additional tuples:Pros and Cons
✅ Advantages:- Supports user-defined roles
- Flexible permission assignment
- No model changes needed for new role instances
- More complex than static relations
- Requires additional tuples for role-permission mapping
Approach 3: Role Assignments
The previous approach works well when custom roles are global for the organization. However, if you need roles that can be attached to different object instances with different members for each instance, you need role assignments.Example: Project-Specific Admin Roles
Let’s say you want a “Project Admin” role where each project can have different admins, but the role permissions remain consistent.Step 1: Define the Role and its Permissions
Define arole type where you list all the permissions that any role can have:
A “Project Admin” role can have can_view_project and can_edit_project:
Step 2: Assign Users to a Role on an Entity
Add arole_assignment type to assign users to the role:
Step 3: Connect to Your Objects
Define anorganization type with an admin role. Then, define a project type that links to an organization and a role_assignment. Note that we are combining a static admin role with custom role assignments. We recommend to always use static roles when they are known in advance.
Setting Up Role Assignments
- Create the role assignment instance:
- Link the role assignment to the project:
- Link the project to an organization:
Pros and Cons
✅ Advantages:- Maximum flexibility for instance-specific roles
- Reusable role definitions across different objects
- Fine-grained control over role membership
- Most complex approach to implement
- Requires careful planning of the role hierarchy
- More tuples needed for setup and maintenance
Choosing the Right Approach
Decision Tree
-
Do you need user-defined roles?
- No → Use Relations as Roles
- Yes → Continue to step 2
-
Do roles need different members per object instance?
- No → Use Simple User-Defined Roles
- Yes → Use Role Assignments
Performance Considerations
- Relations as Roles: Fastest evaluation
- Simple User-Defined Roles: Moderate performance impact
- Role Assignments: Highest performance impact
Best Practices
- Start simple: Begin with relations as roles and evolve as needed
- Hybrid approach: Combine static relations for well-known roles with dynamic roles for custom ones
- Documentation: Clearly document your role model for your team
- Functional Testing: Write tests to verify your model behaves as expected
- Performance Testing: Test performance with realistic data volumes
Related Sections
Check out these related resources for more information about adopting OpenFGA.Custom Roles Step by Step
Follow a detailed walkthrough of implementing custom roles.
Multi-tenant RBAC Example
See a complete multi-tenant role-based access control implementation.
Role Assignments Example
Explore a full role assignments implementation.