RBAC vs ABAC vs ACL vs ReBAC: Choosing an Access Control Model
Access control models differ in one thing: what an authorization decision is based on.
RBAC vs ABAC in short: RBAC grants permissions to roles and assigns roles to users, so it answers "what can editors do?" easily but cannot say "only their own documents" without a role per document. ABAC evaluates conditions on attributes of the user, the resource and the environment, so it handles ownership, department and time rules naturally but is harder to audit. Most applications use RBAC for features and add ABAC conditions for records; the last example on this page does both in one Casbin model.
| نموذج | Decides on | Example rule |
|---|---|---|
| ACL (access control list) | The user | alice may edit design.md |
| RBAC (role-based) | The user's roles | editors may edit documents |
| ABAC (attribute-based) | Attributes of the user, the resource, and the context | owners may edit their documents; people in the same department may read them |
| ReBAC (relationship-based) | Relationships between the user and the resource | anyone who is a viewer of the folder may read the documents in it |
| PBAC (policy-based) | Rule expressions stored as policy | whatever condition the policy row contains |
These are not competing products: they are ways of writing rules, and real systems mix them. In Casbin each one is a few lines of model configuration, and you can switch or combine them without changing your application code. This page expresses the same small example in each model so that the differences are concrete.
The example: a document app with one document, design.md, owned by alice. alice should be able to edit it, bob should be able to read it, and nobody else should have access.
ACL
An access control list states, for each user, what they may do with each object.
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
p, alice, design.md, read
p, alice, design.md, edit
p, bob, design.md, read
- Good at: small systems and per-object sharing ("share this file with bob"). Every decision is easy to explain.
- Weak at: scale. With u users and o objects the list grows toward u × o rows, and when someone changes jobs you must find and edit all of their rows.
RBAC
Role-based access control puts roles between users and permissions. Permissions are granted to roles, and users are assigned roles.
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
p, editor, design.md, read
p, editor, design.md, edit
p, viewer, design.md, read
g, alice, editor
g, bob, viewer
g, carol, viewer
Giving carol read access was one g line; she inherits everything viewer can do. Roles can also inherit from other roles (g, editor, viewer), and RBAC with domains gives a user different roles in different tenants.
- Good at: permissions that follow job functions. It is easy to audit ("what can an editor do?", "who is an admin?"), and onboarding or offboarding is a role change.
- Weak at: rules about specific records. "Authors may edit their own articles" cannot be written with roles alone; trying leads to one role per record, known as role explosion.
RBAC vs ACL: an ACL is RBAC without the roles. Start with RBAC unless you really have only a handful of users, because adding roles later means rewriting every rule.
Tutorials: Go, Node.js, NestJS, Python, Java, Rust, gRPC.
ABAC
Attribute-based access control evaluates conditions on attributes of the user (department, clearance), the resource (owner, status, sensitivity), and the environment (time, IP address). In Casbin you pass objects to Enforce() and read their fields in the matcher.
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub.Name == r.obj.Owner || (r.act == 'read' && r.sub.Department == r.obj.Department)
There is no policy file: alice may edit design.md because she is its owner, and bob may read it because he works in the same department. A new document in the design department is readable by bob without any change to the rules.
- Good at: rules that depend on the record or on context: ownership, department, document status, business hours, region. One rule replaces many role grants.
- Weak at: auditing. "Who can read this document?" has no direct answer; you have to evaluate the conditions against every user. Conditions also need the attributes at hand, which means loading the record before the check.
With the eval() pattern, conditions move from the model into policy rows, so they can be added and removed at runtime like any other rule.
Tutorials: Go, Node.js with Express, Python with Flask.