RBAC in practice: Implementing secure authorization for your application
Complete guide to Role-Based Access Control (RBAC): Master permission design, role management, and secure authorization with practical CMS implementation.
Complete guide to Role-Based Access Control (RBAC): Master permission design, role management, and secure authorization with practical CMS implementation.
Are you struggling with implementing a secure and scalable authorization system for your application? Role-Based Access Control (RBAC) is the industry standard for managing user permissions, but implementing it correctly can be challenging. This tutorial will show you how to build a robust RBAC system using a real-world Content Management System (CMS) example.
By following this guide, you'll learn:
The complete source code for this tutorial is available on GitHub.
Role-Based Access Control is more than just assigning permissions to users. It's about creating a structured approach to authorization that balances security with maintainability.
You can learn more about What is RBAC in the Auth Wiki.
Here are the key principles we'll follow in our implementation:
Fine-grained permissions give you precise control over what users can do in your system. Instead of broad access levels like "admin" or "user", we define specific actions users can perform on resources. For example:
read:articles - View any article in the systemcreate:articles - Create new articlesupdate:articles - Modify existing articlespublish:articles - Change the publication status of articlesResource ownership is a fundamental concept in our CMS's authorization design. While RBAC defines what actions different roles can perform, ownership adds a personal dimension to access control:
update:articles permission, an author can still edit their own articlesThis dual-layer approach (roles + ownership) creates a more intuitive and secure system. Publishers and admins can still manage all content through their role permissions, while authors maintain control over their own work.
Let's start by designing our CMS's core functionality through its API endpoints:
For each endpoint, we need to consider two aspects of access control:
Here's how we'll handle access for each endpoint:
| Endpoint | Access control logic |
|---|---|
| GET /api/articles | - Anyone with list:articles permission, OR authors can see their own articles |
| GET /api/articles/:id | - Anyone with read:articles permission, OR author of the article |
| POST /api/articles | - Anyone with create:articles permission |
| PATCH /api/articles/:id | - Anyone with update:articles permission, OR author of the article |
| DELETE /api/articles/:id | - Anyone with delete:articles permission, OR author of the article |
| PATCH /api/articles/:id/published | - Only users with publish:articles permission |
Based on our API access requirements, we can define these permissions:
| Permission | Description |
|---|---|
| list:articles | View the list of all articles in the system |
| read:articles | Read any article's full content |
| create:articles | Create new articles |
| update:articles | Modify any article |
| delete:articles | Delete any article |
| publish:articles | Change publication status |
Note that these permissions are only needed when accessing resources you don't own. Article owners can automatically:
read:articles needed)update:articles needed)delete:articles needed)Now that we have our API and permissions defined, we can create roles that group these permissions logically:
| Permission/Role | ๐ Admin | ๐ Publisher | โ๏ธ Author |
|---|---|---|---|
| Description | Full system access for complete content management | Can view all articles and control publication status | Can create new articles in the system |
| list:articles | โ | โ | โ |
| read:articles | โ | โ | โ |
| create:articles | โ | โ | โ |
| update:articles | โ | โ | โ |
| delete:articles | โ | โ | โ |
| publish:articles | โ | โ | โ |
Note: Authors automatically have read/update/delete permissions for their own articles, regardless of role permissions.
Each role is designed with specific responsibilities in mind:
This role structure creates a clear separation of concerns:
Before you start, you need to create a account in Logto Cloud, or you can also use an self-hosted Logto instance by using the Logto OSS version.
But for this tutorial, we will use Logto Cloud for simplicity.

list:articlesread:articlescreate:articlesupdate:articlespublish:articlesdelete:articles
Go to Roles in Logto Console to create the following roles for the CMS
read:articles, list:articles, publish:articlescreate:articles


Go to the "User management" section in Logto Console to create users.
In the user details's "Roles" tab, you can assign roles to the user.
In our example, we create 3 users with the following roles:


Now, we have setup RBAC in Logto, we can start to integrate it into our frontend.
First, follow the Logto Quick Starts to integrate Logto into your application.
In our example, we use React for demonstration.
After you have setup Logto in your application, we need to add the RBAC configurations for Logto to work.
Remember to sign out and sign in again to make this change take effect if you are already signed in.
When the user sign-in with Logto and request an access token for the API resources specified above, Logto will add scopes (permissions) related to the user's role to the access token.
You can use getAccessTokenClaims from useLogto hook to get the scopes from the access token.
And you can use the userScopes to check if the user has the permission to access the resource.
Now, it's time to integrate Logto RBAC into your backend.
First, we need to add a middleware in the backend to check user permissions, verify if the user is logged in, and determine whether they have the necessary permissions to access certain APIs.
As you can see, in this middleware, we verify whether the frontend request contains a valid access token and check if the access token's audience matches the API resource we created in the Logto Console.
The reason for verifying the API resource is that our API resource actually represents the resources of our CMS backend, and all our CMS permissions are associated with this API resource.
Since this API resource represents the CMS resources in Logto, in our frontend code, we include the corresponding Access token when making API requests to the backend:
Now we can use the requireAuth middleware to protect our API endpoints.
For APIs that should only be accessible to users with specific permissions, we can add restrictions directly in the middleware. For example, the article creation API should only be accessible to users with the create:articles permission:
For APIs that need to check both permissions and resource ownership, we can use the hasScopes function. For example, in the article listing API, users with the list:articles permission can access all articles, while authors can access their own created articles:
At this point, we have completed the RBAC implementation. You can checkout the complete source code to see the full implementation.
Now, let's test our CMS RBAC implementation using the three users we just created.
First, let's sign in as Alex and Charles respectively and create some articles.
Since Alex has the Admin role, they can create, delete, update, publish, and view all articles.

Charles, having the Author role, can only create their own articles and can only view, update, and delete articles they own.

Bob, with the Publisher role, can view and publish all articles but cannot create, update, or delete them.

Congratulations! You've learned how to implement a robust RBAC system in your application.
For more complex scenarios, such as building multi-tenant applications, Logto provides comprehensive organization support. Check out our guide Build a multi-tenant SaaS application: A complete guide from design to implementation to learn more about implementing organization-wide access control.
Happy coding! ๐