How to Set Up RBAC Roles and Permissions, Step by Step

Diagram of RBAC: users Priya, Sam and Lee hold Viewer, Editor and Admin roles that grant permissions on blog articles

Role-based access control (RBAC) is a way of deciding who can do what in an app by giving permissions to roles and then giving roles to people, instead of granting permissions to each person directly. Setting up RBAC roles and permissions well means you stop managing every user by hand and start managing kinds of work.

This guide follows a small company blog with three people, Priya, Sam and Lee, from an empty system to clean, tested and reviewed access. Each section is one stage in order, with concrete checks you can apply to your own app.

In short
  • Permissions go to roles, and roles go to people. Never attach a permission straight to a user.
  • Start by listing every resource and the actions it allows, named like articles:edit.
  • Build a few roles from real job functions and give each one only what the job needs.
  • Test with a sample account, and confirm that denied actions really fail on the server.
  • Review role assignments regularly, because access slowly piles up over time.
  1. 0:00Intro
  2. 0:24What You'll Build and Need
  3. 1:07Why Roles Beat Per-User Permissions
  4. 2:13See the Three Layers of RBAC
  5. 2:59List the Actions Each Resource Allows
  6. 3:57Define Roles From Real Job Functions
  7. 5:01Name Roles After Jobs, Not People
  8. 5:55Attach Only the Needed Permissions
  9. 6:54Check the Permission Matrix
  10. 7:39Assign Each User One or More Roles
  11. 8:38Test With a Sample Account
  12. 9:33Confirm Denied Actions Really Fail
  13. 10:28Fix the Most Common RBAC Mistakes
  14. 11:21Review Assignments on a Regular Rhythm
  15. 12:16The Six Steps to Clean Access
  16. 12:48Think in Roles, Grant the Minimum

Gather what you need before you start

Be clear about the goal first: every person gets access through a role, never through a one-off permission. One-off permissions are what turn into a mess months later. A useful rule of thumb is that if someone has access and you can't name the role that gave it to them, something slipped through.

You don't need a special tool to plan any of this. A simple spreadsheet is enough to sketch the whole model, and fixing a mistake in a spreadsheet is far easier than fixing one in a live system.

  • A list of your users
  • The resources you want to protect, such as articles or billing pages
  • The actions people take on them, such as read or edit
  • A test account you can sign in with for the final checks

Understand why roles beat per-user permissions

Picture setting every teammate's permissions one at a time. Each new hire means copying someone else's settings and hoping they were right. Each departure means hunting through every screen to remove access. Sooner or later you lose track of who can edit what, and mistakes build up without anyone noticing.

With per-user access, each person carries a private list of permissions and nothing ties those lists together. Two people doing the same job slowly drift apart. Role-based access fixes this by keeping permissions in one place, on the role itself. When Sam joins as an editor, Sam gets the Editor role and inherits what it allows.

The bigger benefit shows up later. Update a role once, and everyone who holds it is updated too. You stop asking what each person can do and start asking what each kind of job needs.

Map the three layers of RBAC

RBAC has a simple shape. Users hold roles, roles hold permissions, and permissions act on resources. On our blog, Priya holds Viewer, Sam holds Editor and Lee holds Admin. Viewer carries articles:view. Editor carries articles:view and articles:edit. Admin carries users:delete, plus much more in a real system.

Read the picture left to right: people on one side, the things you protect on the other, and roles and permissions in the middle as the bridge. Notice what's missing. No line runs straight from a person to a permission. That rule keeps RBAC clean, and it's the one most worth protecting as your app grows. Every step below fills in one part of this picture.

List the actions each resource allows

Step one is writing down everything that can actually be done. Without this list, you end up designing roles around guesses. On the blog, articles can be viewed, created, edited and deleted. Comments, users and billing each get their own, shorter list. Think of the result as a menu that roles will pick from later.

Join each resource and action into a single name, such as articles:edit. Anyone reading a role later can tell exactly what each permission does. To find actions, walk through your app's buttons, and pay attention to the quiet ones. Exporting data or changing many records at once are easy to forget, and they are often among the riskiest.

  • Every resource you protect appears on the list
  • Every action uses the resource:action format
  • Exports, downloads and bulk changes are included
# resource: actions it allows
articles: [view, create, edit, delete]
comments: [view, create, delete]
users:    [view, invite, delete]
billing:  [view, edit]

Define roles from real job functions

Step two is deciding who orders from the menu. Base roles on what people actually do each day, not on individuals. Ask simple questions: who only reads, who creates and changes content, and who manages accounts and settings? Each clear answer is a candidate role. For the blog, that gives three: Viewer for managers, auditors and new teammates who need to look but not change anything; Editor for people who create and edit content but don't manage users or billing; and Admin for managing users, roles and settings.

Name roles after jobs, not people. A role called Sam's Access breaks the moment Sam leaves or a second person needs that job. A name like Temp Fix tells you nothing, and nobody will dare delete it. A good test: could you hand this role to a brand new person tomorrow without changing it?

Watch out for role explosion. When every small exception gets its own role, you end up with one role per person, which is just per-user access in disguise. Start with a few roles and add more only when a real need appears.

  • Each role is named after a kind of work, like Editor or Support Agent
  • Each role has a one-line purpose, such as "for staff who write and edit articles"
  • The Admin group is kept very small

Attach only the permissions each role needs

Step three connects roles to the actions from step one. The guiding rule is least privilege: each role gets only what the job truly needs, nothing extra just in case. This isn't about punishing anyone. It limits how much damage one misused account or one wrong click can do.

In the blog's configuration, the viewer gets only articles:view, the editor gets view and edit, and the admin uses a star, which means every action on articles, users and billing. A practical way to work is to start each role empty and add permissions one at a time, asking whether the job really needs each one. If the answer is maybe, leave it out for now.

Then check the result as a permission matrix, with actions as rows and roles as columns. On the blog, everyone can view, editors and admins can edit, and only admins can delete or manage users and billing. If a cell makes you pause, ask why. That pause is usually where extra access is hiding.

  • Every role started empty and grew one permission at a time
  • Wildcards (*) are used only for true admins, since they also grant actions added later
  • Delete, user management and billing are limited to the roles that need them
# role: the permissions it gets
viewer: [articles:view]
editor: [articles:view, articles:edit]
admin:  [articles:*, users:*, billing:*]

Assign roles to users, never raw permissions

Step four is where people finally get access. Priya gets Viewer, Sam gets Editor and Lee gets Admin. Because the thinking already happened when you designed the roles, this step should feel almost boring, and that's a good sign. If you're tempted to give one person a single extra permission, treat it as a signal that a role is missing or needs adjusting.

A person can hold more than one role. Maya writes articles and also handles invoices, so she holds Editor and a Billing role. Roles add together, so she gets everything from both. That's useful, but it means you should check each person's combined access, not just each role on its own. If your tool supports groups, assign a role to a team, such as the content team, and add people to the group.

  • Every user receives access only through roles
  • Users with several roles have had their combined permissions checked
  • Groups are used where your tool supports them
# user: roles they hold
priya: [viewer]
sam:   [editor]
lee:   [admin]
maya:  [editor, billing]

Test allowed and denied actions with a sample account

Assigning roles isn't finished until you've tested them. Don't use your own admin account for this, because admins can do everything and will hide problems. Create a separate test user for each role you care about and sign in through the normal login screen, just like a real user. Shortcuts or special test modes can skip the very checks you're trying to test.

Walk through one case. A test editor signs in and tries to delete a post. The system looks up their roles and finds editor, gathers that role's permissions (view and edit), and checks the requested action, articles:delete. It isn't on the list, so the response is 403 Forbidden.

Test in both directions. Make sure the editor can still edit, so nobody is locked out, and make sure forbidden actions really fail. Hiding a button is only cosmetic. Try the action directly, for example from another tool, and confirm the server refuses it.

  • Each role can still perform its allowed actions
  • Each role gets a clear error for one action it should never do
  • Forbidden actions are refused by the server, not just hidden in the interface

Fix common mistakes and review access regularly

Most RBAC problems fall into two groups: people have more access than intended, or access that once made sense was never removed. The usual culprits are overlapping roles that combine into too much access, old roles kept after a job change, buttons that are hidden but still work, and making everyone an admin. The fixes are to review each user's combined permissions, remove roles at every job change, enforce checks on the server, and start with minimal access.

Most of these aren't setup mistakes. They're drift, with access slowly piling up over months. That's why regular cleanup matters as much as good setup. Treat an access review as a loop: list every user and their roles, ask team owners to confirm each one is still needed, remove the extras, write down what changed, and repeat. Each round gets quicker because there's less left to clean up.

  • Roles are updated when someone joins, changes jobs or leaves
  • A short review runs every few months
  • Changes from each review are recorded
  • The number of admin accounts stays as small as possible

Key takeaways

  • Give permissions to roles and roles to users, never permissions straight to people.
  • List every resource and action first, and name permissions as resource:action.
  • Build a few roles from real job functions and name them after the work.
  • Apply least privilege and use wildcards only for true admins.
  • Test with separate sample accounts and confirm denied actions fail on the server.
  • Review assignments regularly and at every join, job change or departure.

Frequently asked questions

What is the difference between a role and a permission in RBAC?

A permission is a single allowed action on a resource, such as articles:edit. A role is a named bundle of permissions that matches a kind of work, such as Editor. Users receive roles, and they get their permissions through those roles.

Can a user have more than one role?

Yes. When someone holds two roles, they get everything both roles allow, added together. Because of that, always check the combined access for people with multiple roles, since two roles can add up to more than anyone intended.

How many roles should a small app start with?

A few roles cover most small apps. The blog example uses three: Viewer, Editor and Admin. Add new roles only when a real need appears, and avoid creating a custom role for each person.

Is hiding a button enough to block an action?

No. Hiding a button is only cosmetic. The permission check has to run on the server, so test by calling the action directly and confirming it is refused.

How often should I review role assignments?

A short review every few months is a good habit, but don't rely on the calendar alone. Update roles whenever someone joins, changes jobs or leaves, since those are the moments when access most often goes wrong.

What if roles alone can't express a rule I need?

Some access rules depend on more than a person's job, and roles alone can't handle them. Attribute-based access control (ABAC) is an approach designed for those cases.

Watch the full video on YouTube →

Souy Soeng

Souy Soeng

Hi there 👋, I’m Soeng Souy (StarCode Kh)
-------------------------------------------
🌱 I’m currently creating a sample Laravel and React Vue Livewire
👯 I’m looking to collaborate on open-source PHP & JavaScript projects
💬 Ask me about Laravel, MySQL, or Flutter
⚡ Fun fact: I love turning ☕️ into code!

Post a Comment

CAN FEEDBACK
Ad