What is PBAC? Policy-Based Access Control in Casbin
What is PBAC?
Policy-based access control (PBAC) keeps authorization rules as policy data, separate from application code, and evaluates them at runtime. Changing who may do what means editing a policy, not shipping a new release, which is why PBAC is often chosen when security or compliance teams own the rules.
In Casbin, PBAC means storing rule expressions in policy rows and evaluating them with eval(). Unlike fixed role or attribute checks in the model, each policy row can carry its own condition.
Policies can include:
- Dynamic expressions: evaluated per request (e.g.
r.sub.Age >= 18) - Complex logic: boolean and comparison operators, attribute access
- Context: user, resource, and environment attributes
- Business rules: domain-specific logic in policy
PBAC vs ABAC vs RBAC
RBAC and ABAC describe what a decision is based on: roles, or attributes. PBAC describes how the rules are managed: as policy evaluated at runtime. The two overlap. The examples on this page are ABAC conditions managed as PBAC, and a Casbin RBAC policy is also data that can change at runtime. In practice, "PBAC" is used for systems where the rule logic itself, not only the assignments, lives in policy. Choosing an access control model compares the models on one example.
Model
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub_rule, obj_rule, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = eval(p.sub_rule) && eval(p.obj_rule) && r.act == p.act
p.sub_rule/p.obj_rule— expressions over the request (e.g.r.sub.Age >= 18,r.obj.Level >= 1)eval()— evaluates these expressions at enforce time
Examples
Basic Policy
Policy:
p, r.sub.Age >= 18, r.obj.Level >= 1, play
Request Examples:
{"Age":25}, {"Level":2}, play # ALLOWED (Age >= 18 and Level >= 1)
{"Age":16}, {"Level":2}, play # DENIED (Age < 18)
{"Age":20}, {"Level":0}, play # DENIED (Level < 1)
{"Age":25}, {"Level":2}, read # DENIED (action doesn't match policy)
Complex Policy
Policy:
p, r.sub.Department == "IT" && r.sub.Level >= 3, r.obj.Confidential == false, read
Request Examples:
{"Department":"IT","Level":3}, {"Confidential":false}, read # ALLOWED
{"Department":"IT","Level":2}, {"Confidential":false}, read # DENIED (Level < 3)
{"Department":"HR","Level":3}, {"Confidential":false}, read # DENIED (Department != "IT")
{"Department":"IT","Level":3}, {"Confidential":true}, read # DENIED (Confidential == true)
Code Example:
e, _ := NewEnforcer("examples/pbac_model.conf", "examples/pbac_policy.csv")
// Enable JSON request support
e.EnableAcceptJsonRequest(true)
// Define subject and object with attributes
subject := `{"Department": "IT", "Level": 3}`
object := `{"Confidential": false}`
action := "read"
// Check permission
ok, err := e.Enforce(subject, object, action)
if err != nil {
fmt.Printf("Enforcement error: %v\n", err)
return
}
if ok {
fmt.Println("Permission granted")
} else {
fmt.Println("Permission denied")
}
With EnableAcceptJsonRequest(true), parameters that look like JSON ({ or [) are parsed automatically; invalid JSON returns a clear error.

Comments are powered by giscus and GitHub Discussions. They load from giscus.app and GitHub only after you click the button below.