vengtoo

package module
v1.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 25, 2026 License: MIT Imports: 11 Imported by: 0

README

Vengtoo Go SDK

Early access0.x releases may have breaking changes. Pin your version if stability matters.

Go client for Vengtoo — works with both Vengtoo Cloud and the Vengtoo Agent.

Install

go get github.com/vengtoo/vengtoo-go@v0.1.0

Usage

Cloud Mode
package main

import (
    "context"
    "fmt"
    vengtoo "github.com/vengtoo/vengtoo-go"
)

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

    allowed, err := client.Check(context.Background(),
        vengtoo.Subject{ID: "user:123", Type: "user", Roles: []string{"editor"}},
        "read",
        vengtoo.Resource{Type: "document", ID: "doc:456"},
    )
    if err != nil {
        panic(err)
    }
    fmt.Println("Allowed:", allowed)
}
OAuth2 Client Credentials

For service-to-service auth, use an OAuth2 client (client_id + client_secret, where the secret is prefixed azx_cs_). The SDK exchanges credentials at the token endpoint, caches the JWT in memory, and refreshes ~60s before expiry.

client := vengtoo.NewClient("",
    vengtoo.WithOAuth("my-client-id", "azx_cs_..."),
)

Equivalent curl for the underlying token exchange:

curl -X POST https://api.vengtoo.com/identity-srv/v1/oauth/token \
  -d grant_type=client_credentials \
  -d client_id=my-client-id \
  -d client_secret=azx_cs_...

Providing both an API key and WithOAuth(...) is rejected. A bad client_id / client_secret surfaces as a distinct *vengtoo.OAuthError (check with vengtoo.IsOAuthError(err)) with a message telling you to recheck your credentials.

Agent Mode (local)
client := vengtoo.NewClient("", vengtoo.WithBaseURL("http://localhost:8181"))
Full Authorize Response
resp, err := client.Authorize(ctx, &vengtoo.AuthorizeRequest{
    Subject:  vengtoo.Subject{ID: "user:123", Type: "user"},
    Resource: vengtoo.Resource{Type: "document", ID: "doc:456"},
    Action:   vengtoo.Action{Name: "read"},
    Context:  map[string]interface{}{"ip": "10.0.0.1"},
})
// resp.Decision (bool), resp.Context.Reason, resp.Context.PolicyID, resp.Context.AccessPath
net/http Middleware
mux := http.NewServeMux()
mux.Handle("/documents/", client.HTTPMiddleware("document", "read", "X-User-ID")(handler))
Gin Middleware
func AuthzMiddleware(client *vengtoo.Client, resourceType, action string) gin.HandlerFunc {
    return func(c *gin.Context) {
        allowed, err := client.Check(c.Request.Context(),
            vengtoo.Subject{ID: c.GetHeader("X-User-ID"), Type: "user"},
            action,
            vengtoo.Resource{Type: resourceType, ID: c.Param("id")},
        )
        if err != nil || !allowed {
            c.AbortWithStatusJSON(403, gin.H{"error": "forbidden"})
            return
        }
        c.Next()
    }
}

router.GET("/documents/:id", AuthzMiddleware(client, "document", "read"), handler)
Options
vengtoo.NewClient(apiKey,
    vengtoo.WithBaseURL("http://localhost:8181"),  // Custom URL
    vengtoo.WithHTTPClient(customHTTPClient),       // Custom http.Client
    vengtoo.WithTimeout(5 * time.Second),           // Custom timeout
    vengtoo.WithRetries(3),                         // Max retries on 5xx/429 (default: 2)
)

Error Handling

resp, err := client.Authorize(ctx, req)
if err != nil {
    if vengtoo.IsAuthError(err) {
        // 401 — bad API key or expired token
    }
    if vengtoo.IsForbidden(err) {
        // 403
    }
    if vengtoo.IsOAuthError(err) {
        // bad client_id / client_secret
    }
    if vengtoo.IsServerError(err) {
        // 5xx — retries exhausted
    }
}

The SDK automatically retries on 5xx and 429 responses (default: 2 retries with linear backoff). 4xx errors are never retried. With OAuth, a 401 triggers one token refresh before failing.

Types

Type Fields
Subject ID, Type, Attributes, Properties, Roles
Resource Type, ID, Attributes, Properties
AuthorizeRequest Subject, Resource, Action, Context
AuthorizeResponse Decision, Context *AuthorizeContext
AuthorizeContext Reason, ReasonCode, PolicyID, AccessPath
Error StatusCode, Message
OAuthError StatusCode, Code, Description

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsAuthError

func IsAuthError(err error) bool

IsAuthError returns true if the error is a 401 Unauthorized.

func IsForbidden

func IsForbidden(err error) bool

IsForbidden returns true if the error is a 403 Forbidden.

func IsNotFound

func IsNotFound(err error) bool

IsNotFound returns true if the error is a 404 Not Found.

func IsOAuthError

func IsOAuthError(err error) bool

IsOAuthError returns true if err is an *OAuthError.

func IsServerError

func IsServerError(err error) bool

IsServerError returns true if the error is a 5xx server error.

Types

type Action

type Action struct {
	Name       string                 `json:"name"`
	Properties map[string]interface{} `json:"properties,omitempty"`
}

Action represents an authorization action (AuthZEN 1.0).

type AuthorizeContext

type AuthorizeContext struct {
	Reason     string `json:"reason,omitempty"`
	ReasonCode string `json:"reason_code,omitempty"`
	PolicyID   string `json:"policy_id,omitempty"`
	AccessPath string `json:"access_path,omitempty"`
	// HITL fields — present when reason_code is "authorization_pending".
	AuthReqID  string `json:"auth_req_id,omitempty"`
	ApprovalID string `json:"approval_id,omitempty"`
	ExpiresIn  int    `json:"expires_in,omitempty"`
	Interval   int    `json:"interval,omitempty"`
}

AuthorizeContext holds detailed context about an authorization decision.

type AuthorizeRequest

type AuthorizeRequest struct {
	Subject  Subject                `json:"subject"`
	Resource Resource               `json:"resource"`
	Action   Action                 `json:"action"`
	Context  map[string]interface{} `json:"context,omitempty"`
}

AuthorizeRequest is the input for an authorization check.

type AuthorizeResponse

type AuthorizeResponse struct {
	Decision bool              `json:"decision"`
	Context  *AuthorizeContext `json:"context,omitempty"`
}

AuthorizeResponse is the result of an authorization check.

type BatchEvalItem

type BatchEvalItem struct {
	Subject  *Subject               `json:"subject,omitempty"`
	Action   *Action                `json:"action,omitempty"`
	Resource *Resource              `json:"resource,omitempty"`
	Context  map[string]interface{} `json:"context,omitempty"`
}

BatchEvalItem is a single evaluation within a batch request. Nil fields inherit from the top-level defaults in BatchEvaluationRequest.

type BatchEvaluationRequest

type BatchEvaluationRequest struct {
	Subject     *Subject               `json:"subject,omitempty"`
	Action      *Action                `json:"action,omitempty"`
	Resource    *Resource              `json:"resource,omitempty"`
	Context     map[string]interface{} `json:"context,omitempty"`
	Evaluations []BatchEvalItem        `json:"evaluations"`
	Options     *BatchOptions          `json:"options,omitempty"`
}

BatchEvaluationRequest is the input for a batch authorization check (AuthZEN 1.0 POST /access/v1/evaluations).

type BatchEvaluationResponse

type BatchEvaluationResponse struct {
	Evaluations []AuthorizeResponse `json:"evaluations"`
}

BatchEvaluationResponse is the result of a batch authorization check.

type BatchOptions

type BatchOptions struct {
	EvaluationsSemantic string `json:"evaluations_semantic,omitempty"`
}

BatchOptions configures batch evaluation behavior.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is the Vengtoo SDK client.

func NewClient

func NewClient(apiKey string, opts ...ClientOption) *Client

NewClient creates a new Vengtoo client. For cloud with API key: vengtoo.NewClient("azx_...") For cloud with OAuth: vengtoo.NewClient("", vengtoo.WithOAuth("client-id", "azx_cs_...")) For local agent: vengtoo.NewClient("", vengtoo.WithBaseURL("http://localhost:8181"))

func NewClientWithOptions

func NewClientWithOptions(opts ...ClientOption) (*Client, error)

NewClientWithOptions builds a client using only options (no positional API key). It returns an error if the combination of auth options is invalid (e.g. both apiKey and OAuth provided, or neither for a non-local base URL).

Existing callers should continue using NewClient; this constructor is for callers who want construction-time validation of their auth config.

func (*Client) Authorize

func (c *Client) Authorize(ctx context.Context, req *AuthorizeRequest) (*AuthorizeResponse, error)

Authorize sends a full authorization request and returns the detailed response.

func (*Client) AuthorizeBatch

func (c *Client) AuthorizeBatch(ctx context.Context, req *BatchEvaluationRequest) (*BatchEvaluationResponse, error)

AuthorizeBatch sends a batch evaluation request (AuthZEN 1.0) and returns detailed responses for each evaluation item.

func (*Client) AuthorizeWithPolling added in v1.1.2

func (c *Client) AuthorizeWithPolling(ctx context.Context, req *AuthorizeRequest, opts *PollingOptions) (*AuthorizeResponse, error)

AuthorizeWithPolling is like Authorize but handles HITL polling automatically.

If the initial response is authorization_pending, it waits for a human to approve in the Vengtoo dashboard, polling at the server-recommended interval. Returns an AuthorizeResponse in all cases — never returns an error for pending/timeout/network errors, so every outcome is handled uniformly.

Distinct reason_codes in the returned context:

"approval_timeout" — no human responded within the timeout
"polling_error"    — network errors persisted beyond MaxNetworkErrors retries

func (*Client) Check

func (c *Client) Check(ctx context.Context, subject Subject, action string, resource Resource, reqCtx ...map[string]interface{}) (bool, error)

Check is a convenience method that returns just the boolean result. It accepts action as a plain string for ergonomics and wraps it into an Action object internally.

func (*Client) CheckBatch

func (c *Client) CheckBatch(ctx context.Context, req *BatchEvaluationRequest) ([]bool, error)

CheckBatch is a convenience method that returns just the boolean decisions.

func (*Client) CreateDelegation added in v1.1.2

func (c *Client) CreateDelegation(ctx context.Context, req *CreateDelegationRequest) (*Delegation, error)

CreateDelegation grants delegate the ability to act on behalf of delegator. The delegation is enforced server-side at every authorization check — the delegate's effective permissions are the intersection of its own policies and the delegator's policies (scope attenuation, not escalation).

func (*Client) HTTPMiddleware

func (c *Client) HTTPMiddleware(resourceType, action, subjectIDHeader string) func(http.Handler) http.Handler

HTTPMiddleware returns a net/http middleware that checks authorization. subjectIDHeader is the header containing the subject ID (e.g., "X-User-ID").

func (*Client) RevokeDelegation added in v1.1.2

func (c *Client) RevokeDelegation(ctx context.Context, id string) error

RevokeDelegation revokes an existing delegation by ID. Once revoked, the delegate immediately loses the delegator's permission scope.

func (*Client) WithDelegation added in v1.1.2

func (c *Client) WithDelegation(ctx context.Context, req *CreateDelegationRequest, fn func(delegationID string) error) error

WithDelegation creates a delegation, calls fn with the delegation ID, then always revokes the delegation — even if fn panics or returns an error. This ensures the agent never retains access beyond the task boundary.

Example:

err := client.WithDelegation(ctx, &vengtoo.CreateDelegationRequest{
    DelegatorID: johnEntityID,
    DelegateID:  workflowEntityID,
}, func(delegationID string) error {
    return runWorkflow(ctx)
})

type ClientOption

type ClientOption func(*Client)

ClientOption configures the client.

func WithBaseURL

func WithBaseURL(url string) ClientOption

WithBaseURL sets a custom base URL (e.g., "http://localhost:8181" for local agent).

func WithHTTPClient

func WithHTTPClient(hc *http.Client) ClientOption

WithHTTPClient sets a custom HTTP client.

func WithOAuth

func WithOAuth(clientID, clientSecret string) ClientOption

WithOAuth configures OAuth2 Client Credentials authentication. The SDK will exchange these credentials for a short-lived bearer token at https://api.vengtoo.com/v1/oauth/token (or the URL set via WithOAuthTokenURL), cache it in memory, and refresh it ~60s before expiry. Mutually exclusive with providing an API key to NewClient.

func WithOAuthTokenURL

func WithOAuthTokenURL(tokenURL string) ClientOption

WithOAuthTokenURL overrides the OAuth2 token endpoint URL. Intended for tests (point at a mock token server). Has no effect unless WithOAuth is also supplied.

func WithRetries

func WithRetries(n int) ClientOption

WithRetries sets the max number of retries on transient (5xx) errors. Default is 2.

func WithTimeout

func WithTimeout(d time.Duration) ClientOption

WithTimeout sets the HTTP client timeout.

type CreateDelegationRequest added in v1.1.2

type CreateDelegationRequest struct {
	DelegateID  string     `json:"delegate_id"`
	DelegatorID string     `json:"delegator_id"`
	ExpiresAt   *time.Time `json:"expires_at,omitempty"`
}

CreateDelegationRequest creates a delegation so that delegate acts on behalf of delegator.

type Delegation added in v1.1.2

type Delegation struct {
	ID          string     `json:"id"`
	DelegateID  string     `json:"delegate_id"`
	DelegatorID string     `json:"delegator_id"`
	ExpiresAt   *time.Time `json:"expires_at,omitempty"`
	RevokedAt   *time.Time `json:"revoked_at,omitempty"`
	CreatedAt   time.Time  `json:"created_at"`
}

Delegation represents an active or revoked delegation record.

type Error

type Error struct {
	StatusCode int
	Message    string
}

Error represents an AuthzX API error with status code and message.

func (*Error) Error

func (e *Error) Error() string

type OAuthError

type OAuthError struct {
	StatusCode  int
	Code        string // RFC 6749 error code, e.g. "invalid_client"
	Description string
}

OAuthError represents a failure during the OAuth2 Client Credentials token exchange. It is distinct from Error (which wraps API-call failures) so customers can tell "bad client_id/client_secret" apart from "bad authorization request".

func (*OAuthError) Error

func (e *OAuthError) Error() string

type PollingOptions added in v1.1.2

type PollingOptions struct {
	// Timeout is how long to wait for human approval. Default: 5 minutes.
	Timeout time.Duration
	// MaxNetworkErrors is the max consecutive network failures before returning
	// a polling_error result. Default: 3.
	MaxNetworkErrors int
	// OnPending is called once when the request first enters authorization_pending
	// state. authReqID and expiresIn may be empty/zero if not returned by server.
	OnPending func(authReqID string, expiresIn int)
}

PollingOptions configures AuthorizeWithPolling behavior.

type Resource

type Resource struct {
	ID         string                 `json:"id,omitempty"`
	ExternalID string                 `json:"external_id,omitempty"`
	Type       string                 `json:"type,omitempty"`
	Properties map[string]interface{} `json:"properties,omitempty"`
}

Resource represents the target of the action.

type Subject

type Subject struct {
	ID         string                 `json:"id,omitempty"`
	ExternalID string                 `json:"external_id,omitempty"`
	Type       string                 `json:"type,omitempty"`
	Properties map[string]interface{} `json:"properties,omitempty"`
}

Subject represents the entity performing the action.

Directories

Path Synopsis
examples
basic command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL