What is RBAC? Role-Based Access Control in Casbin
What is RBAC?
Role-based access control (RBAC) grants permissions to roles instead of to individual users, and gives each user one or more roles. To let a new employee do their job you assign them a role such as editor or billing; to change what all editors can do you change the role once.
RBAC has three parts:
- Users: people or services that make requests.
- Roles: named job functions, such as
admin,editororviewer. - Permissions: an action on a resource, such as
editon/articles.
A request is allowed when one of the user's roles holds the permission. Roles can also inherit from other roles: if editor inherits from viewer, editors get everything viewers can do. RBAC was formalized by NIST in the 1990s, and the RBAC96 family of models describes the variants: flat roles, role hierarchies and constraints. See RBAC vs. RBAC96 for how Casbin maps to them.
A minimal RBAC model and policy in Casbin:
[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, article, edit
p, viewer, article, read
g, editor, viewer
g, alice, editor
g, bob, viewer
alice may edit and read articles (editor inherits viewer); bob may only read them.
RBAC vs ABAC: RBAC is easy to audit but cannot say "only their own records" without creating a role per record. ABAC adds conditions on attributes such as the owner or the time of day, and most applications combine both. Choosing an access control model compares ACL, RBAC, ABAC and ReBAC on one example.
Tutorials: add RBAC to a web API in Go with Gin, Node.js with Express, NestJS, Python with FastAPI, Java with Spring Boot, Rust or gRPC. You can also try the RBAC examples in the online editor.
Role definition
The [role_definition] section defines RBAC role (inheritance) relationships. Casbin can run several RBAC systems at once: one for users (with role inheritance) and optionally one for resources. Each is independent.
This section is optional; omit it if you are not using RBAC.
[role_definition]
g = _, _
g2 = _, _
Here g and g2 are two role systems; _, _ means each has two sides (e.g. user and role). Use only g for user roles; add g2 when resources have roles too. Examples: rbac_model.conf, rbac_with_resource_roles_model.conf.
User–role (and resource–role) mappings are stored in the policy, for example:
p, data2_admin, data2, read
g, alice, data2_admin
So alice has role data2_admin. Casbin treats all names as strings (user, resource, or role).
Use the role in a matcher:
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
So the request is allowed only if the request subject has the role given in the policy.
- Casbin only stores and evaluates user–role (and resource–role) mappings; it does not validate that users or roles exist. That is the job of authentication.
- Do not reuse the same name for a user and a role (e.g. user
aliceand rolealice), since Casbin cannot tell them apart. Use a prefix (e.g.role_alice) if needed. - Role inheritance is transitive and unbounded: if A has role B and B has role C, then A effectively has role C.
The subject in the policy is usually named sub and listed first. In Go Casbin you can use other names and order; then you must call e.SetFieldIndex("p", constant.SubjectIndex, index) after creating the enforcer so that APIs like DeleteUser use the correct column.
# `subject` here is for sub
[policy_definition]
p = obj, act, subject
e.SetFieldIndex("p", constant.SubjectIndex, 2) // index starts from 0
ok, err := e.DeleteUser("alice") // without SetFieldIndex, it will raise an error