- Notifications
You must be signed in to change notification settings - Fork0
Casagrande-Lucas/go-acl
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation

Access control, roles, and permissions (RBAC + Policy/Ability) for Go APIs — maximum performance, flexibility, and decoupling.
- RBAC (Role-Based Access Control): Define roles, permissions, and users dynamically.
- Policy/Ability Pattern: Advanced authorization logic for complex business requirements.
- Fully Decoupled: Pure Go, zero framework dependencies. Compatible with any HTTP stack (Gin, Gorilla, Fiber, Echo, Chi, etc.).
- Native Middlewares: Ready-to-use with
net/http, easily adaptable for any framework. - Extensible: Implement your own Store (in-memory, SQL, Redis, etc) and plug it in easily.
go get github.com/Casagrande-Lucas/go-acl
go-acl provides everything you need for robust, scalable, and reusable access control in any Go API—from monoliths to microservices.
package mainimport ("net/http""github.com/Casagrande-Lucas/go-acl")funcmain() {store:=acl.NewMemoryStore()// Create roles and usersadminRole:=&acl.Role{Name:"admin",Permissions:map[string]struct{}{"user:create": {},"user:delete": {}}}store.AddRole(adminRole)user:=&acl.User{ID:"1",Roles: []*acl.Role{adminRole}}// Directly populate the user mapstore.Users()["1"]=userauthz:=acl.NewAuthorizer(store)// RBAC-protected routehttp.Handle("/admin",acl.RBACMiddleware(authz,"user:create",func(r*http.Request)*acl.User {id:=r.Header.Get("X-User-ID")u,_:=store.GetUser(id)returnu })(http.HandlerFunc(func(w http.ResponseWriter,r*http.Request) {w.Write([]byte("admin area")) })))http.ListenAndServe(":8080",nil)}
authz.RegisterPolicy("edit_post",func(user*acl.User,resourceany)bool {post,ok:=resource.(map[string]any)if!ok {returnfalse }returnpost["owner_id"]==user.ID})http.Handle("/post/edit",acl.PolicyMiddleware(authz,"edit_post",func(r*http.Request)*acl.User {id:=r.Header.Get("X-User-ID")u,_:=store.GetUser(id)returnu },func(r*http.Request)any {// Simulated resource fetchreturnmap[string]any{"owner_id":r.Header.Get("X-User-ID")} },)(http.HandlerFunc(func(w http.ResponseWriter,r*http.Request) {w.Write([]byte("edit permitted"))})))
go-acl is pure Go and hasno direct dependencies on any web framework.
To integrate with frameworks like Gin or Gorilla, simply create adapters in your application.
import ("github.com/gin-gonic/gin""github.com/Casagrande-Lucas/go-acl")funcRBACGinMiddleware(authz*acl.Authorizer,permstring,userFromContextfunc(*gin.Context)*acl.User) gin.HandlerFunc {returnfunc(c*gin.Context) {user:=userFromContext(c)ifuser==nil||!authz.HasPermission(user,perm) {c.AbortWithStatusJSON(403, gin.H{"error":"forbidden"})return }c.Next() }}// Usager:=gin.Default()r.GET("/admin",RBACGinMiddleware(authz,"user:create",func(c*gin.Context)*acl.User {id:=c.GetHeader("X-User-ID")u,_:=store.GetUser(id)returnu}),func(c*gin.Context) {c.JSON(200, gin.H{"status":"admin ok"})})
funcPolicyGinMiddleware(authz*acl.Authorizer,actionstring,userFromContextfunc(*gin.Context)*acl.User,resourceFromContextfunc(*gin.Context)any) gin.HandlerFunc {returnfunc(c*gin.Context) {user:=userFromContext(c)resource:=resourceFromContext(c)ifuser==nil||!authz.Can(user,action,resource) {c.AbortWithStatusJSON(403, gin.H{"error":"forbidden"})return }c.Next() }}// Usage for editing a post (only owner can edit)r.PUT("/post/:id/edit",PolicyGinMiddleware(authz,"edit_post",func(c*gin.Context)*acl.User {id:=c.GetHeader("X-User-ID")u,_:=store.GetUser(id)returnu },func(c*gin.Context)any {// Simulate resource loadreturnmap[string]any{"owner_id":c.GetHeader("X-User-ID")} },),func(c*gin.Context) {c.JSON(200, gin.H{"status":"edit permitted"})})
With Gorilla Mux, you can use the middleware as-is, since it follows the standardhttp.Handler interface:
import ("github.com/gorilla/mux""github.com/Casagrande-Lucas/go-acl""net/http")r:=mux.NewRouter()r.Handle("/admin",acl.RBACMiddleware(authz,"user:create",userFromRequest)(http.HandlerFunc(adminHandler),)).Methods("GET")
Note:
Middleware adapters for Gin, Echo, Fiber, etc.are not provided in the core library — this keeps the core decoupled, lightweight, and framework-agnostic.
Implement adapters in your application as needed.
You can implement your own Store (SQL, Redis, etc.) by following theStore interface:
typeStoreinterface {GetUser(userIDstring) (*User,error)GetRole(roleNamestring) (*Role,error)AddRole(role*Role)errorAssignRoleToUser(userID,roleNamestring)errorAddPermissionToRole(roleName,permNamestring)error}
import ("gorm.io/gorm""github.com/Casagrande-Lucas/go-acl")// GORM ModelstypeUserstruct {IDstring`gorm:"primaryKey"`Roles []Role`gorm:"many2many:user_roles;"`}typeRolestruct {IDstring`gorm:"primaryKey"`NamestringPermissions []Permission`gorm:"many2many:role_permissions;"`}typePermissionstruct {IDstring`gorm:"primaryKey"`Namestring}// Implementation (minimal)typeGormStorestruct {db*gorm.DB }func (s*GormStore)GetUser(userIDstring) (*acl.User,error) {vardbUserUseriferr:=s.db.Preload("Roles.Permissions").First(&dbUser,"id = ?",userID).Error;err!=nil {returnnil,err }roles:=make([]*acl.Role,0)for_,r:=rangedbUser.Roles {perms:=map[string]struct{}{}for_,p:=ranger.Permissions {perms[p.Name]=struct{}{} }roles=append(roles,&acl.Role{Name:r.Name,Permissions:perms}) }return&acl.User{ID:dbUser.ID,Roles:roles},nil}
Usage with GORM (but works with PostgreSQL, MySQL, etc):
import"gorm.io/driver/sqlite"funcmain() {db,_:=gorm.Open(sqlite.Open("acl.db"),&gorm.Config{})db.AutoMigrate(&User{},&Role{},&Permission{})store:=&GormStore{db:db}authz:=acl.NewAuthorizer(store)// Use authz as in the other examples}
To run unit tests (with coverage):
gotest -cover ./...To generate a coverage HTML report:
gotest -coverprofile=coverage.out ./...go tool cover -html=coverage.out- Native support for SQL/NoSQL stores
- Official adapters for Gin, Echo, Fiber, and other frameworks
- Auditing/logging hooks
- Advanced documentation for policies and abilities
- Multi-tenant support
Contributions are welcome!
Please open an issue, submit a pull request, or share your feedback.
Questions, suggestions, or corporate proposals?
Contact LinkedInLucas Casagrande.
About
Access control, roles, and permissions (RBAC + Policy/Ability) for Go APIs — maximum performance, flexibility, and decoupling.
Topics
Resources
Uh oh!
There was an error while loading.Please reload this page.