Skip to content
Back to skills

Implementing Casbin

ASecurity

Implement role-based (RBAC) and attribute-based (ABAC) access control in Go using Casbin. Covers model configuration, GORM adapters, Chi/gRPC middleware, and production patterns. Use when implementing authorization in Go services.

  • 4 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 12, 2026
databasesgobashsqltestinggitapidatabaseperformancedocumentation

Works with

  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 12, 2026

npx -y skills add aibot88/sec_skill_store --skill implementing-casbin --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Implementing Casbin?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Implementing Casbin
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/aibot88-implementing-casbin/badge)](https://www.skillsdirectory.com/skills/aibot88-implementing-casbin)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: implementing-casbin
description: Implement role-based (RBAC) and attribute-based (ABAC) access control in Go using Casbin. Covers model configuration, GORM adapters, Chi/gRPC middleware, and production patterns. Use when implementing authorization in Go services.
version: 1.0.0
---

# Implementing Casbin Authorization

## Purpose

Implement fine-grained authorization in Go services using Casbin's policy-based access control. Supports RBAC (role-based), ABAC (attribute-based), and hybrid models with database-backed policy storage.

## When NOT to Use

- Simple API key authentication (use middleware directly)
- Single-user applications (no authorization needed)
- OAuth/OIDC token validation only (use dedicated auth libraries)
- Static, compile-time permissions (use Go interfaces/types)

---

## Quick Start Workflow

### Step 1: Install Dependencies

```bash
go get github.com/casbin/casbin/v2
go get github.com/casbin/gorm-adapter/v3
go get gorm.io/driver/postgres  # or mysql
```

### Step 2: Create Model File

Create `config/rbac_model.conf`:

```ini
[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) && keyMatch2(r.obj, p.obj) && r.act == p.act
```

### Step 3: Initialize Enforcer with GORM

```go
package authz

import (
    "fmt"
    "github.com/casbin/casbin/v2"
    gormadapter "github.com/casbin/gorm-adapter/v3"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

func NewEnforcer(dsn, modelPath string) (*casbin.Enforcer, error) {
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    if err != nil {
        return nil, fmt.Errorf("connect to database: %w", err)
    }

    adapter, err := gormadapter.NewAdapterByDB(db)
    if err != nil {
        return nil, fmt.Errorf("create adapter: %w", err)
    }

    e, err := casbin.NewEnforcer(modelPath, adapter)
    if err != nil {
        return nil, fmt.Errorf("create enforcer: %w", err)
    }

    e.EnableAutoSave(true)
    return e, nil
}
```

### Step 4: Add Chi Middleware

```go
func Authorize(e *casbin.Enforcer) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            user, ok := r.Context().Value("userID").(string)
            if !ok || user == "" {
                http.Error(w, "Unauthorized", http.StatusUnauthorized)
                return
            }

            allowed, err := e.Enforce(user, r.URL.Path, r.Method)
            if err != nil {
                http.Error(w, "Authorization error", http.StatusInternalServerError)
                return
            }
            if !allowed {
                http.Error(w, "Forbidden", http.StatusForbidden)
                return
            }
            next.ServeHTTP(w, r)
        })
    }
}
```

### Step 5: Define Policies

```go
// Add role
e.AddRoleForUser("alice", "admin")

// Add permissions for role
e.AddPolicy("admin", "/api/users/*", "GET")
e.AddPolicy("admin", "/api/users/*", "POST")

// Check permission
allowed, _ := e.Enforce("alice", "/api/users/123", "GET")  // true
```

---

## Model Configuration

### RBAC Model (Recommended Default)

```ini
[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) && keyMatch2(r.obj, p.obj) && r.act == p.act
```

**Key parts:**
- `g(r.sub, p.sub)`: Role inheritance (user -> role)
- `keyMatch2`: Supports `/path/:id` patterns

### ABAC Model

```ini
[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
```

**Example:**
```go
// User can only access their own documents
e.AddPolicy("r.sub.ID == r.obj.OwnerID", "r.obj.Type == 'document'", "read")
```

### RBAC with Domains (Multi-Tenant)

```ini
[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 && keyMatch2(r.obj, p.obj) && r.act == p.act
```

**Example:**
```go
e.AddRoleForUserInDomain("alice", "admin", "tenant1")
e.AddPolicy("admin", "tenant1", "/api/*", "GET")
allowed, _ := e.Enforce("alice", "tenant1", "/api/users", "GET")  // true
```

---

## GORM Adapter Setup

### PostgreSQL

```go
dsn := "host=localhost user=app password=secret dbname=myapp port=5432 sslmode=disable"
db, _ := gorm.Open(postgres.Open(dsn), &gorm.Config{})
adapter, _ := gormadapter.NewAdapterByDB(db)
```

### MySQL

```go
dsn := "user:password@tcp(localhost:3306)/myapp?charset=utf8mb4&parseTime=True"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
adapter, _ := gormadapter.NewAdapterByDB(db)
```

### Connection Pooling

```go
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
```

---

## Policy Management

### Adding Policies

```go
e.AddPolicy("alice", "/api/users", "GET")           // Direct permission
e.AddRoleForUser("alice", "admin")                  // Assign role
e.AddRolesForUser("bob", []string{"viewer", "editor"})  // Multiple roles
```

### Removing Policies

```go
e.RemovePolicy("alice", "/api/users", "GET")
e.RemoveFilteredPolicy(0, "alice")    // All policies for subject
e.DeleteRoleForUser("alice", "admin")
```

### Querying Policies

```go
policies, _ := e.GetPolicy()                          // All policies
roles, _ := e.GetRolesForUser("alice")               // User's roles
permissions, _ := e.GetImplicitPermissionsForUser("alice")  // Including inherited
hasRole, _ := e.HasRoleForUser("alice", "admin")
```

---

## Testing

### Unit Test Setup

```go
func TestEnforcer(t *testing.T) {
    modelText := `
[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
`
    m, _ := model.NewModelFromString(modelText)
    e, _ := casbin.NewEnforcer(m)

    e.AddPolicy("admin", "/users", "GET")
    e.AddRoleForUser("alice", "admin")

    allowed, _ := e.Enforce("alice", "/users", "GET")
    assert.True(t, allowed)
}
```

See TEMPLATES.md for complete test templates.

---

## Common Issues

### Policies not persisting

```go
e.EnableAutoSave(true)  // Enable auto-save
// Or: e.SavePolicy()   // Manual save
```

### keyMatch not working with path params

Use correct matcher function:
- `keyMatch2`: `/users/:id` patterns
- `keyMatch3`: `/users/{id}` patterns

### Slow performance with large policy sets

```go
// Load only relevant policies
filter := gormadapter.Filter{P: []string{"", "tenant1"}}
e.LoadFilteredPolicy(filter)

// Or batch enforcement
results, _ := e.BatchEnforce(requests)
```

---

## Integration with Other Skills

- **setup-go**: Run before Casbin setup
- **quality-check**: Lint authorization code
- **run-tests**: Execute authorization tests

---

## References

- [Casbin Documentation](https://casbin.org/docs/en/overview)
- [GORM Adapter](https://github.com/casbin/gorm-adapter)
- See **REFERENCE.md** for complete API reference and built-in functions
- See **TEMPLATES.md** for copy-paste middleware and test templates

Files in this skill

  • SKILL.md7.3 KB
  • source.json759 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.