Vengtoo + Gin
Add authorization to your Gin API in 5 minutes.
Install
go get github.com/vengtoo/vengtoo-go
Set up the client
package main
import (
"os"
vengtoo "github.com/vengtoo/vengtoo-go"
)
var client = vengtoo.NewClient(os.Getenv("VENGTOO_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(),
vengtoo.Subject{ID: userID, Type: "user"},
action,
vengtoo.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(),
vengtoo.Subject{ID: userID, Type: "user", Roles: roles},
action,
vengtoo.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.Evaluate(c.Request.Context(), &vengtoo.EvaluationRequest{
Subject: vengtoo.Subject{ID: c.GetHeader("X-User-ID")},
Resource: vengtoo.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 = vengtoo.NewClient("", vengtoo.WithBaseURL("http://localhost:8181"))
No API key needed. Same middleware, evaluated locally, with no round-trip to the cloud.
Error handling
allowed, err := client.Check(ctx, subject, action, resource)
if err != nil {
if vengtoo.IsAuthError(err) {
// Invalid API key — check configuration
}
if vengtoo.IsServerError(err) {
// Vengtoo server error — already retried
}
}