Skip to main content

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
}
}