Skip to main content

Go SDK

Install

go get github.com/vengtoo/vengtoo-go

Source: github.com/vengtoo/vengtoo-go

Quick start

package main

import (
"context"
"fmt"
"log"

vengtoo "github.com/vengtoo/vengtoo-go"
)

func main() {
client := vengtoo.NewClient("azx_...")

decision, err := client.Check(context.Background(),
vengtoo.Subject{ExternalID: "user_2xK9mP", Type: "user"},
"read",
vengtoo.Resource{ExternalID: "doc_7fQr1N", Type: "document"},
)
if err != nil {
log.Fatal(err)
}
fmt.Println("Decision:", decision)
}

ExternalID is whatever ID your system already assigns — a database primary key, a ULID, a slug. ID is also accepted if you have Vengtoo's internal UUID.

Using with the local agent

client := vengtoo.NewClient("", vengtoo.WithBaseURL("http://localhost:8181"))

Same API, no code changes needed.

Full response

resp, err := client.Authorize(ctx, &vengtoo.AuthorizeRequest{
Subject: vengtoo.Subject{ExternalID: "user_2xK9mP", Type: "user"},
Resource: vengtoo.Resource{ExternalID: "doc_7fQr1N", Type: "document"},
Action: vengtoo.Action{Name: "read"},
Context: map[string]interface{}{"ip": "10.0.0.1"},
})
// resp.Decision, resp.Context.Reason, resp.Context.PolicyID, resp.Context.AccessPath

Middleware

The examples below demonstrate type-level authorization — checking whether a subject can perform an action on a resource type, without targeting a specific instance. This is the most common starting point and works for the majority of use cases.

How you implement middleware in practice will vary based on where your subject ID lives (JWT claim, session, header), how your routes are structured, and whether you need instance-level checks. Adapt these to fit your setup.

func AuthzMiddleware(client *vengtoo.Client, resourceType, action string) gin.HandlerFunc {
return func(c *gin.Context) {
// The subject ExternalID is whatever ID your system uses for this actor —
// a JWT sub claim, a session user ID, or a primary key from your own database.
allowed, err := client.Check(c.Request.Context(),
vengtoo.Subject{ExternalID: c.GetHeader("X-User-ID"), Type: "user"},
action,
vengtoo.Resource{Type: resourceType},
)
if err != nil || !allowed {
c.AbortWithStatusJSON(403, gin.H{"error": "forbidden"})
return
}
c.Next()
}
}

router.GET("/documents/:id", AuthzMiddleware(client, "document", "read"), handler)
router.POST("/documents", AuthzMiddleware(client, "document", "create"), handler)

Batch evaluation

Check multiple subject/resource/action combinations in a single request (up to 50):

evals := []vengtoo.BatchEvalItem{
{Subject: &vengtoo.Subject{ExternalID: "user_2xK9mP", Type: "user"}, Action: &vengtoo.Action{Name: "read"}, Resource: &vengtoo.Resource{ExternalID: "doc_7fQr1N", Type: "document"}},
{Subject: &vengtoo.Subject{ExternalID: "user_2xK9mP", Type: "user"}, Action: &vengtoo.Action{Name: "delete"}, Resource: &vengtoo.Resource{ExternalID: "doc_7fQr1N", Type: "document"}},
{Subject: &vengtoo.Subject{ExternalID: "user_9pLx3T", Type: "user"}, Action: &vengtoo.Action{Name: "read"}, Resource: &vengtoo.Resource{ExternalID: "doc_7fQr1N", Type: "document"}},
}

results, err := client.CheckBatch(ctx, &vengtoo.BatchEvaluationRequest{Evaluations: evals})
if err != nil {
log.Fatal(err)
}

for i, allowed := range results {
fmt.Printf("%s %s on %s → %v\n",
evals[i].Subject.ExternalID,
evals[i].Action.Name,
evals[i].Resource.ExternalID,
allowed,
)
}
// user_2xK9mP read on doc_7fQr1N → true
// user_2xK9mP delete on doc_7fQr1N → false
// user_9pLx3T read on doc_7fQr1N → false

Results come back in the same order as the input. Keeping a reference to evals lets you zip decisions back to their inputs by index.

For per-item reason codes and access paths use AuthorizeBatch, which returns *BatchEvaluationResponse.

OAuth2 client credentials

Use a client ID and secret instead of an API key — the SDK exchanges them for a short-lived bearer token automatically and refreshes it before expiry:

client := vengtoo.NewClient("",
vengtoo.WithOAuth("client_abc123", "azx_cs_secret"),
)

Options

vengtoo.NewClient(apiKey,
vengtoo.WithBaseURL("http://localhost:8181"),
vengtoo.WithHTTPClient(customClient),
vengtoo.WithTimeout(5 * time.Second),
vengtoo.WithRetries(3),
)

Error handling

resp, err := client.Authorize(ctx, req)
if err != nil {
if vengtoo.IsAuthError(err) {
// 401 — invalid or expired API key
}
if vengtoo.IsOAuthError(err) {
// OAuth token exchange failed — bad client ID or secret
}
if vengtoo.IsNotFound(err) {
// 404 — subject or resource external_id not found
}
if vengtoo.IsServerError(err) {
// 5xx — server error (already retried)
}
}

Types

TypeFields
SubjectType (required), ID, ExternalID, Properties
ResourceType (required), ID, ExternalID, Properties. If neither ID nor ExternalID is set, "*" is sent automatically for type-level policy matching.
ActionName
AuthorizeRequestSubject, Resource, Action, Context
AuthorizeResponseDecision, Context
ResponseContextReason, PolicyID, AccessPath
BatchEvalItemSubject, Action, Resource (all pointers)
BatchEvaluationRequestEvaluations []BatchEvalItem (max 50)
BatchEvaluationResponseEvaluations []AuthorizeResponse