Casbin
Authentication Library
Casbin
Overview
Casbin is a multi-language authorization library that supports various access control models such as ACL, RBAC, and ABAC. With flexible policy definition and model configuration, it can handle complex permission management requirements. It supports over 20 languages including Go, Python, Java, Node.js, and Rust, and is widely adopted as an authorization system for web applications, microservices, and cloud services. As of 2025, it continues active development.
Details
Casbin is an authorization library that can handle various access control models in a unified manner. It features the following key characteristics:
- Multiple Access Control Models: Support for ACL, RBAC, ABAC, RESTful, deny/allow priority, and more
- Flexible Policy Management: Policy storage in CSV, databases, and cloud storage
- Model Configuration: Definition of access control rules and matchers in INI format
- Multi-Language Support: Implementation in over 20 programming languages
- Web Framework Integration: Integration with Express, Flask, Django, Spring Boot, and more
- Distributed System Support: Authorization management in microservices and cloud environments
Pros and Cons
Pros
- Flexibility to handle multiple access control models in a unified manner
- Consistent authorization system across multi-language environments with rich language support
- Clear policy management through model-driven design
- Rich integration options with web frameworks
- Proven track record and reliability in large-scale systems
- Active community and continuous development
Cons
- High initial learning cost and complex configuration in some cases
- Understanding of Casbin concepts required for advanced features
- May be over-featured for small-scale applications
- Optimization required when performance is critical
- Poor model design can make operation difficult
- Debugging and troubleshooting can be complex
Reference Pages
Code Examples
Basic ACL Model Configuration
# model.conf - ACL Model Definition
[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
# policy.csv - ACL Policy
p, alice, data1, read
p, bob, data2, write
p, charlie, data1, read
p, charlie, data1, write
Using Casbin in Go
package main
import (
"fmt"
"github.com/casbin/casbin/v2"
)
func main() {
// Initialize Enforcer
e, err := casbin.NewEnforcer("model.conf", "policy.csv")
if err != nil {
panic(err)
}
// Permission check
res, err := e.Enforce("alice", "data1", "read")
if err != nil {
panic(err)
}
fmt.Printf("Alice can read data1: %t\n", res) // true
res, err = e.Enforce("alice", "data2", "read")
if err != nil {
panic(err)
}
fmt.Printf("Alice can read data2: %t\n", res) // false
// Add policy dynamically
e.AddPolicy("alice", "data2", "read")
res, err = e.Enforce("alice", "data2", "read")
if err != nil {
panic(err)
}
fmt.Printf("Alice can read data2 after adding policy: %t\n", res) // true
// Remove policy
e.RemovePolicy("alice", "data2", "read")
}
RBAC Model Implementation
# rbac_model.conf - RBAC Model Definition
[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
# rbac_policy.csv - RBAC Policy
p, admin, data1, read
p, admin, data1, write
p, admin, data2, read
p, admin, data2, write
p, user, data1, read
g, alice, admin
g, bob, user
g, charlie, user
package main
import (
"fmt"
"github.com/casbin/casbin/v2"
)
func main() {
// Initialize Enforcer with RBAC model
e, err := casbin.NewEnforcer("rbac_model.conf", "rbac_policy.csv")
if err != nil {
panic(err)
}
// Role-based permission check
res, _ := e.Enforce("alice", "data1", "write")
fmt.Printf("Alice (admin) can write data1: %t\n", res) // true
res, _ = e.Enforce("bob", "data1", "write")
fmt.Printf("Bob (user) can write data1: %t\n", res) // false
// Role management API
roles, _ := e.GetRolesForUser("alice")
fmt.Printf("Alice's roles: %v\n", roles) // [admin]
users, _ := e.GetUsersForRole("admin")
fmt.Printf("Admin users: %v\n", users) // [alice]
// Dynamic role assignment
e.AddRoleForUser("charlie", "admin")
res, _ = e.Enforce("charlie", "data2", "write")
fmt.Printf("Charlie (now admin) can write data2: %t\n", res) // true
}
ABAC Model with Attribute-Based Access Control
# abac_model.conf - ABAC Model Definition
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub.Department == r.obj.Owner
package main
import (
"fmt"
"github.com/casbin/casbin/v2"
)
type Subject struct {
Name string
Department string
}
type Object struct {
Name string
Owner string
}
func main() {
// Initialize Enforcer with ABAC model
e, err := casbin.NewEnforcer("abac_model.conf")
if err != nil {
panic(err)
}
// Attribute-based permission check
sub := Subject{Name: "alice", Department: "engineering"}
obj := Object{Name: "project1", Owner: "engineering"}
res, _ := e.Enforce(sub, obj, "read")
fmt.Printf("Alice (engineering) can access engineering project: %t\n", res) // true
obj2 := Object{Name: "project2", Owner: "marketing"}
res, _ = e.Enforce(sub, obj2, "read")
fmt.Printf("Alice (engineering) can access marketing project: %t\n", res) // false
}
Middleware Integration in Web Applications
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/casbin/casbin/v2"
)
func NewCasbinMiddleware(enforcer *casbin.Enforcer) gin.HandlerFunc {
return func(c *gin.Context) {
// Get user information (from JWT token or session)
user := getUserFromToken(c.GetHeader("Authorization"))
// Identify resource and action
resource := c.Request.URL.Path
action := c.Request.Method
// Permission check
allowed, err := enforcer.Enforce(user, resource, action)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Authorization check failed"})
c.Abort()
return
}
if !allowed {
c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
c.Abort()
return
}
c.Next()
}
}
func main() {
// Initialize Casbin
enforcer, _ := casbin.NewEnforcer("model.conf", "policy.csv")
r := gin.Default()
// Apply authorization middleware
authorized := r.Group("/api", NewCasbinMiddleware(enforcer))
{
authorized.GET("/users", getUsers)
authorized.POST("/users", createUser)
authorized.DELETE("/users/:id", deleteUser)
}
r.Run(":8080")
}
func getUserFromToken(token string) string {
// Extract user information from JWT token
// Implementation details omitted
return "alice"
}
func getUsers(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"users": []string{"alice", "bob"}})
}
func createUser(c *gin.Context) {
c.JSON(http.StatusCreated, gin.H{"message": "User created"})
}
func deleteUser(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "User deleted"})
}
RBAC Model with Domain/Tenant Separation
# rbac_with_domains_model.conf
[request_definition]
r = sub, dom, obj, act
[policy_definition]
p = sub, dom, obj, act
[role_definition]
g = _, _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act
# rbac_with_domains_policy.csv
p, admin, tenant1, data1, read
p, admin, tenant1, data1, write
p, admin, tenant2, data2, read
p, user, tenant1, data1, read
g, alice, admin, tenant1
g, bob, user, tenant1
g, charlie, admin, tenant2
package main
import (
"fmt"
"github.com/casbin/casbin/v2"
)
func main() {
// Initialize Enforcer with domain-enabled RBAC model
e, err := casbin.NewEnforcer("rbac_with_domains_model.conf", "rbac_with_domains_policy.csv")
if err != nil {
panic(err)
}
// Domain-specific permission check
res, _ := e.Enforce("alice", "tenant1", "data1", "write")
fmt.Printf("Alice can write data1 in tenant1: %t\n", res) // true
res, _ = e.Enforce("alice", "tenant2", "data2", "read")
fmt.Printf("Alice can read data2 in tenant2: %t\n", res) // false
// Domain-specific role management
roles, _ := e.GetRolesForUserInDomain("alice", "tenant1")
fmt.Printf("Alice's roles in tenant1: %v\n", roles) // [admin]
// Verify cross-tenant access prevention
res, _ = e.Enforce("bob", "tenant2", "data2", "read")
fmt.Printf("Bob (tenant1 user) can read tenant2 data: %t\n", res) // false
}
Policy Management with Database
package main
import (
"github.com/casbin/casbin/v2"
gormadapter "github.com/casbin/gorm-adapter/v3"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
func main() {
// Database connection
db, err := gorm.Open(postgres.Open("postgres://user:password@localhost/casbin_db"), &gorm.Config{})
if err != nil {
panic(err)
}
// Use Gorm Adapter
adapter, err := gormadapter.NewAdapterByDB(db)
if err != nil {
panic(err)
}
// Initialize Enforcer with database adapter
e, err := casbin.NewEnforcer("model.conf", adapter)
if err != nil {
panic(err)
}
// Load policies from database
e.LoadPolicy()
// Dynamic policy management (persisted to database)
e.AddPolicy("alice", "data1", "read")
e.AddPolicy("bob", "data2", "write")
// Save policies
e.SavePolicy()
// Permission check
res, _ := e.Enforce("alice", "data1", "read")
fmt.Printf("Alice can read data1: %t\n", res) // true
}