AuthzX + Gin
Add authorization to your Gin API in 5 minutes.
Install
go get github.com/authzx/authzx-go
Set up the client
package main
import (
"os"
authzx "github.com/authzx/authzx-go"
)
var client = authzx.NewClient(os.Getenv("AUTHZX_API_KEY"))
Create middleware
func AuthzMiddleware(resourceType, action string) gin.HandlerFunc {
return func(c *gin.Context) {
userID := c.GetHeader("X-User-ID")
if userID == "" {
c.AbortWithStatusJSON(401, gin.H{"error": "unauthorized"})
return
}
allowed, err := client.Check(c.Request.Context(),
authzx.Subject{ID: userID, Type: "user"},
action,
authzx.Resource{ID: c.Param("id"), Type: resourceType},
)
if err != nil {
c.AbortWithStatusJSON(500, gin.H{"error": "authorization check failed"})
return
}
if !allowed {
c.AbortWithStatusJSON(403, gin.H{"error": "forbidden"})
return
}
c.Next()
}
}
Apply to routes
r := gin.Default()
r.GET("/documents/:id", AuthzMiddleware("document", "read"), getDocument)
r.PUT("/documents/:id", AuthzMiddleware("document", "write"), updateDocument)
r.DELETE("/documents/:id", AuthzMiddleware("document", "delete"), deleteDocument)
With roles
If your auth middleware sets roles on the context:
func AuthzMiddleware(resourceType, action string) gin.HandlerFunc {
return func(c *gin.Context) {
userID := c.GetString("user_id") // from your auth middleware
roles := c.GetStringSlice("roles") // from your auth middleware
allowed, err := client.Check(c.Request.Context(),
authzx.Subject{ID: userID, Type: "user", Roles: roles},
action,
authzx.Resource{ID: c.Param("id"), Type: resourceType},
)
if err != nil || !allowed {
c.AbortWithStatusJSON(403, gin.H{"error": "forbidden"})
return
}
c.Next()
}
}
Full response with reason
func getDocument(c *gin.Context) {
resp, err := client.Authorize(c.Request.Context(), &authzx.AuthorizeRequest{
Subject: authzx.Subject{ID: c.GetHeader("X-User-ID")},
Resource: authzx.Resource{ID: c.Param("id"), Type: "document"},
Action: "read",
})
if err != nil {
c.JSON(500, gin.H{"error": "authorization failed"})
return
}
if !resp.Allowed {
c.JSON(403, gin.H{"error": "forbidden", "reason": resp.Reason})
return
}
c.JSON(200, gin.H{
"id": c.Param("id"),
"policy": resp.PolicyID,
"path": resp.AccessPath,
})
}
Using the local agent
var client = authzx.NewClient("", authzx.WithBaseURL("http://localhost:8181"))
No API key needed. Same middleware, sub-millisecond responses.
Error handling
allowed, err := client.Check(ctx, subject, action, resource)
if err != nil {
if authzx.IsAuthError(err) {
// Invalid API key — check configuration
}
if authzx.IsServerError(err) {
// AuthzX server error — already retried
}
}