What is Role-Based Access Control (RBAC)?

Last updated: July 2026

Role-based access control is an authorization model where permissions attach to roles, and users get permissions only through their roles. The indirection is the entire idea: nothing is ever granted to a person directly, so organizational change becomes data change — a promotion is a role reassignment, not an archaeology dig through scattered grants. Proposed by Ferraiolo and Kuhn in 1992 as an alternative to the older discretionary and mandatory models, it became the ANSI/INCITS 359 standard and the default authorization vocabulary of enterprise software.

Key takeaways

QuestionAnswer
The indirectionUser → role → permission — never user → permission directly
Role ≠ groupA group collects users; a role collects permissions
The model levelsCore · hierarchical (inheritance) · constrained (separation of duties)
The failure modeRole explosion — attributes encoded as roles until roles outnumber users
The compositionRoles inside ACL entries: RBAC for the many, ACLs for the exceptions

Users, roles, permissions — the indirection at work

Permissions                 Roles                    Users
─────────────               ─────────────            ─────────────
posts:read        ─┐
posts:write        ├──▶     Editor          ◀──────  Ada, Grace
posts:publish     ─┘
users:manage      ─┐
billing:view       ├──▶     Admin           ◀──────  Linus
posts:*           ─┘
posts:read        ────▶     Viewer          ◀──────  everyone else

Ada publishes because Editor carries posts:publish — reassign her role,
and every permission it carried moves with it. One edit, not N.

Roles as live data, wired into object permissions:

// JavaScript / Node.js — Back4app JS SDK
// Roles as data: create a role, add members, grant through it
const roleACL = new Parse.ACL();
roleACL.setPublicReadAccess(true);
const editors = new Parse.Role('Editors', roleACL);
editors.getUsers().add(adaUser);
await editors.save();

// Grant by role, not by user — membership changes in one place
const post = new Parse.Object('Post');
const acl = new Parse.ACL(currentUser);  // owner entry
acl.setRoleWriteAccess('Editors', true); // RBAC meets the object's ACL
post.setACL(acl);
await post.save();

The NIST model, correctly

Most explainers compress the standard into a listicle; the actual structure is worth thirty seconds. Core RBAC defines users, roles, permissions — and sessions, the forgotten element: a user activates a subset of their roles per session, which is how an admin can browse with member powers by default and escalate deliberately. The original paper’s three rules bind it together: act only through a role, hold only authorized roles, do only what the active role permits. Hierarchical RBAC adds inheritance — senior roles subsume junior ones (Manager ⊇ Employee), removing duplication. Constrained RBAC adds separation of duties: static rules forbid conflicting role assignments outright (never both payment-creator and payment-approver); dynamic rules allow the assignment but forbid activating both in one session. And NIST’s sharpest clarification, routinely garbled: a group is a collection of users; a role is a collection of permissions — the role is defined by what it can do, not who is in it.

RBAC structure with sessions and separation of dutiesUsers are assigned roles and activate a subset of them per session. Roles carry permissions and can inherit from junior roles. Separation-of-duty constraints restrict which roles can be assigned or activated together, and permissions apply to resources.

assigned

activates subset
per session

inherits

SoD constraint:
not with Approver

permissions of
active roles

User
Ada

Roles
Editor · Auditor

Session
Editor only

Junior role
Viewer

Conflicting role

posts:write
posts:publish

Resources

Users are assigned roles and activate a subset of them per session. Roles carry permissions and can inherit from junior roles. Separation-of-duty constraints restrict which roles can be assigned or activated together, and permissions apply to resources.

RBAC vs. ACL vs. ABAC

RBACACLABAC
Permissions attach toRolesEach objectAttribute rules
Native questionWhat can this function do?Who can touch this object?Is this allowed in context?
AdministrationOne place per rolePer objectPer policy
Per-object sharingCan’t express itIts home gameExpressible, verbose
Audit “what can Ada do?”Read her rolesScan every objectEvaluate every rule
Failure modeRole explosionList sprawlOpaque policies

The insight the vendor SERP buries: these compose, they don’t compete. Roles handle access that follows function; ACL entries handle per-object exceptions — and the hinge is the role-entry ACE, an ACL line naming a role instead of a user, giving object-level control with one-place membership. Attribute conditions layer on top where context (time, tenant, record state) genuinely decides. “Which one?” is usually the wrong question; “which layer handles which decision?” is the design.

Role explosion — the failure mode

RBAC’s characteristic disease: every exception mints a role, then every project, region, and tenant multiplies them — Project-A-Manager-Region-West-ReadOnly — until roles outnumber users and the audit answer to “who can do what?” is “nobody knows.” The root cause is always the same: contextual attributes encoded as roles. The mitigations, in order: keep attributes out of role names (region and tenant are conditions or scopes, not roles); handle per-object sharing with ACL entries, never per-object roles; scope roles per tenant structurally instead of by name-mangling; and audit — roles nobody holds, permissions no role uses, and grants nobody remembers are drift, and drift is how least privilege quietly dies. A working heuristic: if a role list stops fitting on one screen, the model is absorbing work that belongs to another layer.

Designing roles: top-down, bottom-up, or both

The part no ranking explainer covers: where roles come from. Top-down derives them from the org and its processes — interview the business, name the functions, assign minimal permissions; accurate but slow. Bottom-up mines them from existing grants — cluster who already holds what, and candidate roles fall out; fast but launders past mistakes into policy. Practice is hybrid: mine for candidates, validate against functions, then apply the 80/20 test — a handful of broad roles for the organization’s bulk, exceptions handled by ACLs or conditions rather than boutique roles. And one implementation rule that outlives every reorg: code should check permissions, not role namescan('posts:publish'), not hasRole('Editor') — so redefining a role is a data change, not a refactor, with enforcement server-side, deny-by-default.

Common use cases

  • Admin panels and back-offices — support, moderator, finance, superadmin: functions map cleanly to roles.
  • Content and publishing workflows — author, editor, publisher, with separation between writing and releasing.
  • B2B SaaS team permissions — owner/admin/member/billing per workspace, scoped per tenant.
  • Compliance-bound operations — separation of duties as enforceable role constraints, with role membership as the audit artifact.
  • The role-gate on data layers — roles as the “who” in class-level permissions and row-level policies.

Should you use RBAC? A decision matrix

SituationLean
Access follows job functionRBAC — its home game
Users share individual records ad hocACLs — roles can’t express it
Context decides (time, state, tenant)Attribute conditions over the roles
A handful of user types, stableRBAC with 3–7 broad roles
Deep org charts, nested teamsRole hierarchy — or ReBAC at real scale
”Just admins and everyone else”One role gate — don’t over-model it

Limitations and trade-offs

  • Per-object sharing is out of scope. “Share this document with Ana” has no RBAC answer short of a role per document — that decision belongs to ACLs.
  • Same role, same powers. Two Editors are indistinguishable; individual nuance requires another layer, not a near-duplicate role.
  • Role engineering is real upfront work. Skipping it yields roles that mirror neither the org nor the risk model — and get copied forever.
  • Static roles miss dynamic risk. Role membership doesn’t see unusual hours, new devices, or sensitive record states; that’s attribute territory.
  • Drift is the steady state. Without periodic recertification, role scope only grows; RBAC’s auditability is a capability, not a guarantee.

Roles on Back4app

Back4app is an open-source Backend-as-a-Service (BaaS) platform that combines a managed database, auto-generated REST and GraphQL APIs, authentication, file storage, and Cloud Code serverless functions. Roles here are data, not code: each is an object in the _Role class with a users relation for members and a roles relation for nesting — and nesting is hierarchy for free, since members of a child role inherit whatever its parent roles are granted. The grants themselves happen exactly where the composition section points: role names appear in class-level permissions for the broad strokes and in per-object ACL entries for the exceptions — the code tabs show both halves — with Back4app enforcing the result on every REST, GraphQL, and Live Query request. Because roles are queryable objects, membership management, audits, and admin UIs are ordinary database work: role explosion prevention as a data-modeling habit, not a governance project.

Frequently asked questions

What is RBAC in simple terms?

Access is granted by job function, not per person: permissions attach to roles — Editor, Admin, Support — and users inherit whatever their assigned roles carry. Hiring, promotion, and departure become role changes in one place instead of permission edits scattered everywhere.

What is an example of RBAC?

A content platform with three roles: Admin (everything), Editor (create, edit, publish), Viewer (read only). Ada the editor publishes because Editor carries publish — not because anyone granted Ada anything directly. Reassign her to Viewer and every editing permission vanishes in a single update.

What is the difference between RBAC and ABAC?

RBAC decides from predefined roles; attribute-based access control evaluates attributes of the user, resource, and context — department, sensitivity, time — at request time. RBAC is simpler to reason about and audit; ABAC is finer-grained and harder to debug. Mature systems use RBAC as the baseline and add attribute conditions where context genuinely matters.

What is the difference between RBAC and an ACL?

Direction of attachment: an ACL hangs subject-permission entries on each object; RBAC hangs permissions on roles across the system. They compose rather than compete — an ACL entry can name a role, which is how per-object control and one-place membership management coexist.

What are the RBAC models?

The standard defines core RBAC (users, roles, permissions, sessions), hierarchical RBAC (senior roles inherit junior roles' permissions), and constrained RBAC (separation-of-duty rules — static constraints on assignment, dynamic constraints on what one session may activate together).

What are the three rules of RBAC?

From the original 1992 formulation: a subject can act only through a selected role (role assignment); the subject must be authorized for that role (role authorization); and an action is allowed only if the active role holds its permission (permission authorization). Together: no access except through roles.

What is role explosion?

Uncontrolled role growth when every exception, project, region, or tenant spawns a new role — Project-A-Manager-Region-West — until roles outnumber users and nobody can audit the system. The root cause is encoding contextual attributes as roles instead of handling them with conditions or per-object entries.

Is RBAC the same as least privilege?

No — least privilege is the principle, RBAC is one mechanism for pursuing it, and only role discipline connects them. An over-broad role violates least privilege from inside RBAC; scoping roles minimally and reviewing them periodically is what actually delivers the principle.

What is separation of duties in RBAC?

Constraints that keep conflicting powers apart: static separation blocks one user from ever holding both payment-creator and payment-approver; dynamic separation allows holding both but never activated in the same session. It is fraud prevention expressed as a role rule.

Related terms

Compare with

Further reading

Ready to build your backend?

Start your project on Back4app in minutes — database, auth, APIs, and Cloud Code included. No credit card required.

Written and reviewed by Back4app Engineering, Back4app Engineering · Published 2026-07-27