Setting up Roles and Permissions in Nextjs
Role based access control and Multi-tenancy in Nextjs and React
In this tutorial we will go over an implementation of how to implement Role Based Access Control, commonly referred to as RBAC, in a Nextjs and React app.
To help us with this we can use the most popular RBAC library in the ecosystem, Casl
How Roles based Access Control Works
RBAC is a common and critical feature in modern SAAS apps. It allows Organizations to assign certain permissions to certain roles and assign those roles to specific users.
This allows giving permissions categorically rather than implementing permissions on a per user basis.
An example of this could be and Admin role having permissions to manage an organizations payment information while a Member role would not.
The Admin role user would be able to access the part of the application that can change payment information while the Member role user can't access that part of the app.
Multi Tenancy.
In modern SAAS apps Multi-tenancy is usually used along side RBAC.
Multi-tenancy essentially allows multiple tenants inside of one application, with each tenant having its own data and settings.
An example of this could be an app with multiple Organizations and Teams.
Multi-tenancy and RBAC working together allows a single user to join different teams or orgs with unique roles in each team or org.
Real World Implementation
Here we can look at the implementation that we use in SAAS starterkit.
In Saas Kit we have Orgs we use for multi-tenancy. Each org is isolated from another and has its own data, subscription and settings.
Casl
Overview
Can be other setups or names such as teams or projects.
Role hierarchy
Owners > admins > users
Only one owner per org.
Database setup to work with roles and Orgs
Dataschema for Orgs, Roles, Invite and Users
Roles flow
Owner creates Org.
Owner sends invite to Admin or Member
Admin accepts invite, lands on org-invite page with token. Token used to validate invite.
Data from invite used to create role
Delete invite.
Admin now has access to org.
Owner clicks on remove admin: Role deleted from roles table, admin no longer has access to app.
Can use org_id and user_id to get role for specific user on specific org.
Lets look at each part of the flow in detail with code.
Casl
Now that we have defined our roles we need a way to manage permissions. One way we can do this is manually writing many if(role === “Admin”) statements in our code, but that is very messy and error prone.
We can instead use a library that allows us to centrally manage and define our permissions for each role.
Casl is currently the most popular npm library for managing RBAC (role based access control)
Defining Permissions
Permissions follow a very predictable pattern. We define permissions based on actions on a subject
Actions will be CRUD operations and Subject will be a database model.
For example Actions: “READ”, Subject: “Todos”, here we give permission to read the todos model or table.
This is very similar to SQL row level security pattern
Casl Ability
utils/caslAbility.ts
Casl and Role Context Caslcontext, wrap layout. Role context.
Guarding UI
app/admincard
Guarding Server Actions and check permission function.