warden

package module
v1.5.5 Latest Latest
Warning

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

Go to latest
Published: Jun 18, 2026 License: Apache-2.0 Imports: 16 Imported by: 8

README

Warden — Composable permissions & authorization engine

Go Reference Go Version CI

Warden is a composable authorization engine supporting RBAC, ABAC, and ReBAC in a single unified API. It answers "are you allowed to do this?" and integrates natively with the Forge ecosystem.

Features

  • RBAC — Roles, permissions, role inheritance, resource-scoped assignments
  • ABAC — Attribute-based policies with conditions (IP ranges, time windows, regex, etc.)
  • ReBAC — Zanzibar-style relation tuples with BFS graph walking
  • Multi-model — Use RBAC, ABAC, and ReBAC together; explicit deny > allow > default deny
  • Multi-tenant — All data is tenant-scoped via forge.Scope or standalone context helpers
  • Extensible — Plugin hooks for audit logging, metrics, and custom lifecycle events
  • Caching — Built-in in-memory LRU cache with TTL and per-tenant/subject invalidation
  • Forge native — Drop-in Forge extension with DI, API routes, and middleware

Quick Start

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/xraph/warden"
    "github.com/xraph/warden/assignment"
    "github.com/xraph/warden/id"
    "github.com/xraph/warden/permission"
    "github.com/xraph/warden/role"
    "github.com/xraph/warden/store/memory"
)

func main() {
    ctx := warden.WithTenant(context.Background(), "myapp", "tenant-1")
    s := memory.New()

    eng, err := warden.NewEngine(warden.WithStore(s))
    if err != nil {
        log.Fatal(err)
    }

    // Create role + permission.
    roleID := id.NewRoleID()
    permID := id.NewPermissionID()
    _ = s.CreateRole(ctx, &role.Role{ID: roleID, TenantID: "tenant-1", Name: "editor", Slug: "editor"})
    _ = s.CreatePermission(ctx, &permission.Permission{ID: permID, TenantID: "tenant-1", Name: "doc:read", Resource: "doc", Action: "read"})
    _ = s.AttachPermission(ctx, roleID, permID)

    // Assign role to user.
    _ = s.CreateAssignment(ctx, &assignment.Assignment{
        ID: id.NewAssignmentID(), TenantID: "tenant-1",
        RoleID: roleID, SubjectKind: "user", SubjectID: "alice",
    })

    // Check authorization.
    result, err := eng.Check(ctx, &warden.CheckRequest{
        Subject:  warden.Subject{Kind: warden.SubjectUser, ID: "alice"},
        Action:   warden.Action{Name: "read"},
        Resource: warden.Resource{Type: "doc", ID: "d1"},
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Allowed: %v\n", result.Allowed) // true
}

Installation

Library
go get github.com/xraph/warden
CLI (warden and warden-lsp)

Using go install — recommended if you have a Go toolchain:

go install github.com/xraph/warden/cmd/warden@latest
go install github.com/xraph/warden/cmd/warden-lsp@latest

Pre-built binaries — multi-platform archives (linux / darwin / windows × amd64 / arm64) are attached to every GitHub Release. Each archive contains both warden and warden-lsp.

# Pick a platform from https://github.com/xraph/warden/releases/latest
curl -L -o warden.tar.gz \
  https://github.com/xraph/warden/releases/latest/download/warden-<version>-<os>-<arch>.tar.gz

# Verify the checksum
curl -L -o checksums.txt \
  https://github.com/xraph/warden/releases/latest/download/checksums.txt
shasum -a 256 -c checksums.txt --ignore-missing

tar -xzf warden.tar.gz
sudo mv warden warden-lsp /usr/local/bin/
warden version
VS Code extension
code --install-extension xraph.vscode-warden

Or search for "Warden" in the Extensions panel. See editor/vscode-warden/README.md for a walkthrough.

Architecture

Check Request
     |
     v
+----------+     +---------+     +---------+
|   RBAC   | --> |  ReBAC  | --> |  ABAC   |
| roles &  |     | relation|     | policy  |
| perms    |     | tuples  |     | engine  |
+----------+     +---------+     +---------+
     |                |               |
     +-------+--------+-------+------+
             |                 |
       mergeDecisions    explicit deny
             |            > allow
             v            > default deny
       CheckResult

The engine evaluates all three models and merges results:

  1. Explicit deny (from ABAC) always wins
  2. Any allow from any model grants access
  3. Default deny if no rules match

Authorization Models

RBAC (Role-Based Access Control)

Roles contain permissions. Users are assigned roles (globally or scoped to specific resources). Roles support inheritance via parent chains.

ReBAC (Relationship-Based Access Control)

Zanzibar-style relation tuples (object#relation@subject) with BFS graph walking for transitive permissions. Subject sets enable hierarchical access (e.g., folder membership granting document access).

ABAC (Attribute-Based Access Control)

Policies with conditions evaluate against subject attributes, resource attributes, and request context. Supported operators: eq, neq, in, not_in, contains, starts_with, gt, lt, ip_in_cidr, time_after, time_before, regex, and more.

Store Backends

Warden ships with four pluggable store backends. All implement the composite Store interface from store/store.go.

Backend Package Use case
Memory store/memory Testing, development
PostgreSQL store/postgres Production (Grove ORM, migrations, transactions)
SQLite store/sqlite Embedded / edge deployments (Grove ORM)
MongoDB store/mongo NoSQL / document-oriented workloads (BSON, compound indexes)
import "github.com/xraph/warden/store/memory"
import "github.com/xraph/warden/store/postgres"
import "github.com/xraph/warden/store/sqlite"
import "github.com/xraph/warden/store/mongo"

// Memory (no config needed)
s := memory.New()

// PostgreSQL / SQLite — pass a Grove database instance
s := postgres.New(groveDB)

// MongoDB — pass a Grove MongoDB instance
s := mongo.New(mongoDB)

// All stores support Migrate() for schema setup
_ = s.Migrate(ctx)

Plugin System

Warden provides a granular plugin system with 18 lifecycle hooks. Plugins implement the base plugin.Plugin interface (just Name() string) and opt in to specific hooks by implementing additional interfaces.

import "github.com/xraph/warden/plugin"

type AuditPlugin struct{}

func (p *AuditPlugin) Name() string { return "audit" }

// Opt in to the hooks you care about:
func (p *AuditPlugin) RoleCreated(ctx context.Context, r *role.Role) error {
    log.Printf("role created: %s", r.Name)
    return nil
}
func (p *AuditPlugin) AfterCheck(ctx context.Context, req, result any) error {
    log.Printf("check completed")
    return nil
}
Available Hooks
Category Hook Trigger
Check BeforeCheck(ctx, req) Before authorization evaluation
Check AfterCheck(ctx, req, result) After authorization evaluation
Roles RoleCreated(ctx, role) Role created
Roles RoleUpdated(ctx, role) Role modified
Roles RoleDeleted(ctx, roleID) Role removed
Permissions PermissionCreated(ctx, perm) Permission created
Permissions PermissionDeleted(ctx, permID) Permission removed
Permissions PermissionAttached(ctx, roleID, permID) Permission attached to role
Permissions PermissionDetached(ctx, roleID, permID) Permission detached from role
Assignments RoleAssigned(ctx, assignment) Role assigned to subject
Assignments RoleUnassigned(ctx, assignment) Role unassigned from subject
Relations RelationWritten(ctx, tuple) Relation tuple created
Relations RelationDeleted(ctx, relID) Relation tuple removed
Policies PolicyCreated(ctx, policy) ABAC policy created
Policies PolicyUpdated(ctx, policy) ABAC policy modified
Policies PolicyDeleted(ctx, polID) ABAC policy removed
Lifecycle Shutdown(ctx) Engine shutting down

Hook errors are logged as warnings but never block the caller.

Caching

Warden includes a built-in in-memory LRU cache for Check() results with TTL-based expiration and scoped invalidation.

import "github.com/xraph/warden/cache"

c := cache.NewMemory(
    cache.WithTTL(5 * time.Minute),   // Default: 5m
    cache.WithMaxSize(10000),          // Default: 10,000 entries
)

eng, _ := warden.NewEngine(
    warden.WithStore(s),
    warden.WithCache(c),
)

Cache keys are scoped by tenantID:subjectKind:subjectID:action:resourceType:resourceID.

Invalidation
// Invalidate all cached results for a tenant.
c.InvalidateTenant(ctx, "tenant-1")

// Invalidate all cached results for a specific subject.
c.InvalidateSubject(ctx, "tenant-1", warden.SubjectUser, "alice")

The cache automatically invalidates when roles, permissions, or assignments are modified through the engine.

Middleware

Warden provides HTTP middleware for Forge route protection.

import wardenmw "github.com/xraph/warden/middleware"

// Require a single permission — returns 403 if denied.
router.GET("/documents/:id", handler,
    forge.WithMiddleware(wardenmw.Require(eng, "read", "document")),
)

// RequireAny — allows if ANY check passes (OR logic).
router.POST("/admin/action", handler,
    forge.WithMiddleware(wardenmw.RequireAny(eng,
        warden.CheckRequest{Action: warden.Action{Name: "admin"}, Resource: warden.Resource{Type: "system"}},
        warden.CheckRequest{Action: warden.Action{Name: "write"}, Resource: warden.Resource{Type: "config"}},
    )),
)

// RequireAll — allows only if ALL checks pass (AND logic).
router.DELETE("/documents/:id", handler,
    forge.WithMiddleware(wardenmw.RequireAll(eng,
        warden.CheckRequest{Action: warden.Action{Name: "delete"}, Resource: warden.Resource{Type: "document"}},
        warden.CheckRequest{Action: warden.Action{Name: "admin"}, Resource: warden.Resource{Type: "document"}},
    )),
)

Subject resolution priority:

  1. Authenticated user ID from forge.UserIDFromContext()
  2. Falls back to unknown:anonymous

Configuration

eng, err := warden.NewEngine(
    warden.WithStore(store),                  // Required: store backend
    warden.WithCache(cache),                  // Optional: check result cache
    warden.WithConfig(warden.Config{
        MaxGraphDepth: 10,                    // ReBAC graph traversal depth (default: 10)
        CacheTTL:      5 * time.Minute,       // Check result cache TTL (0 = disabled)
        EnableRBAC:    ptrBool(true),         // Enable RBAC evaluation (default: true)
        EnableABAC:    ptrBool(true),         // Enable ABAC evaluation (default: true)
        EnableReBAC:   ptrBool(true),         // Enable ReBAC evaluation (default: true)
    }),
    warden.WithPlugin(auditPlugin),           // Optional: lifecycle plugins
    warden.WithEvaluator(customEvaluator),    // Optional: custom ABAC evaluator
    warden.WithGraphWalker(customWalker),     // Optional: custom ReBAC graph walker
    warden.WithLogger(logger),                // Optional: structured logger
)

ID System

Warden uses TypeID — UUIDv7-based, K-sortable, URL-safe identifiers with type prefixes for all entities.

role_01h2xcejqtf2nbrexx3vqjhp41
perm_01h2xcejqtf2nbrexx3vqjhp41
asgn_01h2xcejqtf2nbrexx3vqjhp41
Prefixes
Prefix Entity Constructor
role Role id.NewRoleID()
perm Permission id.NewPermissionID()
asgn Assignment id.NewAssignmentID()
wpol Policy id.NewPolicyID()
rel Relation id.NewRelationID()
chklog Check log id.NewCheckLogID()
rtype Resource type id.NewResourceTypeID()
cond Condition id.NewConditionID()
import "github.com/xraph/warden/id"

// Create
roleID := id.NewRoleID()       // role_01h2xce...
permID := id.NewPermissionID() // perm_01h2xce...

// Parse
parsed, err := id.ParseRoleID("role_01h2xcejqtf2nbrexx3vqjhp41")

// Check
if roleID.IsNil() { /* zero-value */ }

// Database support: SQL (Value/Scan), BSON (MarshalBSONValue/UnmarshalBSONValue)

Forge Integration

import (
    "github.com/xraph/forge"
    wardenext "github.com/xraph/warden/extension"
    wardenmw "github.com/xraph/warden/middleware"
)

// Register as Forge extension.
app := forge.New(
    forge.WithExtensions(
        wardenext.New(
            wardenext.WithStore(store),
        ),
    ),
)

// Use middleware for route protection.
router.GET("/documents/:id", handler,
    forge.WithMiddleware(wardenmw.Require(eng, "read", "document")),
)

Examples

See the _examples/ directory:

  • _examples/standalone/ — Warden without Forge
  • _examples/forge/ — Warden as Forge extension
  • _examples/rbac/ — Pure RBAC with role inheritance
  • _examples/rebac/ — Zanzibar-style ReBAC
  • _examples/abac/ — Attribute-based policies

License

Part of the Forge ecosystem.

Documentation

Overview

Package warden provides composable permissions and authorization for Go.

Warden supports RBAC (role-based), ABAC (attribute-based), and ReBAC (relationship-based) authorization models individually or combined. It is tenant-scoped by default via forge.Scope and integrates with the Forge ecosystem for audit logging, feature flags, and async jobs.

eng, err := warden.NewEngine(
    warden.WithStore(memStore),
)
result, err := eng.Check(ctx, &warden.CheckRequest{
    Subject:  warden.Subject{Kind: warden.SubjectUser, ID: "user_123"},
    Action:   warden.Action{Name: "read"},
    Resource: warden.Resource{Type: "document", ID: "doc_456"},
})

Index

Constants

View Source
const MaxNamespaceDepth = 8

MaxNamespaceDepth is the default cap on namespace nesting. Practical organizations don't go deeper than this; the cap keeps walking-cost predictable. Configurable via Config.MaxNamespaceDepth.

Variables

View Source
var (
	// ErrAccessDenied is returned when an authorization check fails.
	ErrAccessDenied = errors.New("warden: access denied")

	// ErrRoleNotFound is returned when a role cannot be found.
	ErrRoleNotFound = errors.New("warden: role not found")

	// ErrPermissionNotFound is returned when a permission cannot be found.
	ErrPermissionNotFound = errors.New("warden: permission not found")

	// ErrAssignmentNotFound is returned when an assignment cannot be found.
	ErrAssignmentNotFound = errors.New("warden: assignment not found")

	// ErrPolicyNotFound is returned when a policy cannot be found.
	ErrPolicyNotFound = errors.New("warden: policy not found")

	// ErrRelationNotFound is returned when a relation tuple cannot be found.
	ErrRelationNotFound = errors.New("warden: relation not found")

	// ErrResourceTypeNotFound is returned when a resource type cannot be found.
	ErrResourceTypeNotFound = errors.New("warden: resource type not found")

	// ErrSystemRoleImmutable is returned when trying to modify a system role.
	ErrSystemRoleImmutable = errors.New("warden: system role cannot be modified")

	// ErrSystemPermissionImmutable is returned when trying to modify a system permission.
	ErrSystemPermissionImmutable = errors.New("warden: system permission cannot be modified")

	// ErrAlreadyExists is the common base error for entity-uniqueness
	// violations. Use errors.Is(err, ErrAlreadyExists) to match any of the
	// specialized ErrDuplicate* errors below.
	//
	// Defined in wardenerr so that low-level subpackages (e.g. store/memory)
	// can return typed duplicate errors without an import cycle.
	ErrAlreadyExists = wardenerr.ErrAlreadyExists

	// ErrDuplicateRole is returned when a role would violate the
	// (tenant_id, namespace_path, slug) uniqueness constraint.
	ErrDuplicateRole = wardenerr.ErrDuplicateRole

	// ErrDuplicatePermission is returned when a permission would violate the
	// (tenant_id, namespace_path, name) uniqueness constraint.
	ErrDuplicatePermission = wardenerr.ErrDuplicatePermission

	// ErrDuplicatePolicy is returned when a policy would violate the
	// (tenant_id, namespace_path, name) uniqueness constraint.
	ErrDuplicatePolicy = wardenerr.ErrDuplicatePolicy

	// ErrDuplicateResourceType is returned when a resource type would violate
	// the (tenant_id, namespace_path, name) uniqueness constraint.
	ErrDuplicateResourceType = wardenerr.ErrDuplicateResourceType

	// ErrDuplicateAssignment is returned when a role is already assigned to a
	// subject within the same scope. Wraps ErrAlreadyExists.
	ErrDuplicateAssignment = wardenerr.ErrDuplicateAssignment

	// ErrDuplicateRelation is returned when a relation tuple already exists.
	// Wraps ErrAlreadyExists.
	ErrDuplicateRelation = wardenerr.ErrDuplicateRelation

	// ErrCyclicRoleInheritance is returned when role inheritance would create a cycle.
	ErrCyclicRoleInheritance = errors.New("warden: cyclic role inheritance detected")

	// ErrMaxMembersExceeded is returned when a role's member limit is reached.
	ErrMaxMembersExceeded = errors.New("warden: role max members exceeded")

	// ErrInvalidCondition is returned when a policy condition is malformed.
	ErrInvalidCondition = errors.New("warden: invalid policy condition")

	// ErrGraphDepthExceeded is returned when the relation graph walk exceeds max depth.
	ErrGraphDepthExceeded = errors.New("warden: relation graph depth exceeded")
)

Functions

func AncestorNamespaces

func AncestorNamespaces(path string) []string

AncestorNamespaces returns the path itself and every ancestor up to the tenant root, ordered from most-specific to most-general. The tenant root (empty string) is always the last element.

Examples:

AncestorNamespaces("")                   → [""]
AncestorNamespaces("eng")                → ["eng", ""]
AncestorNamespaces("eng/platform")       → ["eng/platform", "eng", ""]
AncestorNamespaces("eng/platform/sre")   → ["eng/platform/sre", "eng/platform", "eng", ""]

Used by the engine to resolve roles, permissions, policies, and resource types across the namespace ancestor chain (cascading scope inheritance).

func IsAncestorOrSelf

func IsAncestorOrSelf(ancestor, path string) bool

IsAncestorOrSelf reports whether ancestor is path itself or a strict ancestor of path. Both must be valid namespace paths (or empty string).

func JoinNamespace

func JoinNamespace(parent, child string) string

JoinNamespace concatenates two namespace paths with a "/" separator, dropping empties on either side. Used by the DSL parser to build absolute paths from nested namespace blocks.

func NamespaceFromContext

func NamespaceFromContext(ctx context.Context) string

NamespaceFromContext extracts the namespace path from the given context. Returns the empty string (tenant root) if not set.

func ScopeFromContext

func ScopeFromContext(ctx context.Context) (appID, tenantID string)

ScopeFromContext extracts the tenant scope from the given context. Returns appID and tenantID using the standard resolution chain: explicit WithTenant > forge.Scope > empty.

func ValidateNamespacePath

func ValidateNamespacePath(path string, maxDepth int) error

ValidateNamespacePath checks that a path is well-formed. Empty string (the tenant root) is always valid. Otherwise the path is "/"-separated, each segment matches namespaceSegmentRegex, no reserved segment appears, and depth ≤ maxDepth (or MaxNamespaceDepth if 0).

func WithNamespace

func WithNamespace(ctx context.Context, namespacePath string) context.Context

WithNamespace returns a context with the given namespace path overlaid on top of the existing tenant scope. Pass empty string for the tenant root.

Combine with WithTenant when needed:

ctx := warden.WithTenant(context.Background(), "app1", "t1")
ctx  = warden.WithNamespace(ctx, "engineering/platform")

func WithTenant

func WithTenant(ctx context.Context, appID, tenantID string) context.Context

WithTenant returns a context with the given app and tenant IDs. Use this for standalone mode (without Forge).

Types

type Action

type Action struct {
	Name string `json:"name"`
}

Action represents what the subject wants to do.

type Cache

type Cache interface {
	// Get returns a cached check result, if available.
	Get(ctx context.Context, tenantID string, req *CheckRequest) (*CheckResult, bool)

	// Set stores a check result in the cache.
	Set(ctx context.Context, tenantID string, req *CheckRequest, result *CheckResult)

	// InvalidateTenant removes all cached results for a tenant.
	InvalidateTenant(ctx context.Context, tenantID string)

	// InvalidateSubject removes all cached results for a specific subject.
	InvalidateSubject(ctx context.Context, tenantID string, subjectKind SubjectKind, subjectID string)
}

Cache provides caching for authorization check results.

type CallOption

type CallOption func(*callOptions)

CallOption is a functional option applied per-call on Check, Enforce, and CanI. It is distinct from Option, which configures the Engine at construction time.

func WithCallAppID

func WithCallAppID(appID string) CallOption

WithCallAppID overrides the app ID for this single call.

func WithCallNamespacePath

func WithCallNamespacePath(namespacePath string) CallOption

WithCallNamespacePath overrides the namespace path for this single call. Pass empty string to scope the call to the tenant root.

func WithCallTenantID

func WithCallTenantID(tenantID string) CallOption

WithCallTenantID overrides the tenant ID for this single call. It takes precedence over context-derived scope and CheckRequest.TenantID.

type CheckRequest

type CheckRequest struct {
	Subject       Subject        `json:"subject"`
	Action        Action         `json:"action"`
	Resource      Resource       `json:"resource"`
	Context       map[string]any `json:"context,omitempty"`
	TenantID      string         `json:"tenant_id,omitempty"`      // Optional: overrides context-derived tenant.
	NamespacePath string         `json:"namespace_path,omitempty"` // Optional: overrides context-derived namespace.
}

CheckRequest is the input to an authorization check.

type CheckResult

type CheckResult struct {
	Allowed     bool        `json:"allowed"`
	Decision    Decision    `json:"decision"`
	Reason      string      `json:"reason,omitempty"`
	MatchedBy   []MatchInfo `json:"matched_by,omitempty"`
	Obligations []string    `json:"obligations,omitempty"`
	EvalTimeNs  int64       `json:"eval_time_ns"`
}

CheckResult is the outcome of an authorization check.

Obligations is the list of obligation names from PBAC policies that matched this check (allow OR deny). Obligations are side-effect signals — names of actions the calling system should perform (audit-log, require-mfa, notify-security, etc.). They don't change the Allowed/Decision outcome. The engine also fires the PolicyObligationFired plugin hook per obligation, so existing plugin pipelines (Chronicle audit, dispatchers) get them automatically.

type Config

type Config struct {
	// MaxGraphDepth is the maximum depth for ReBAC graph traversal.
	// Defaults to 10.
	MaxGraphDepth int `json:"max_graph_depth,omitempty"`

	// CacheTTL is the time-to-live for cached check results.
	// Zero means no caching.
	CacheTTL time.Duration `json:"cache_ttl,omitempty"`

	// EnableRBAC enables role-based access control evaluation.
	// Defaults to true.
	EnableRBAC *bool `json:"enable_rbac,omitempty"`

	// EnableABAC enables attribute-based access control evaluation.
	// Defaults to true.
	EnableABAC *bool `json:"enable_abac,omitempty"`

	// EnableReBAC enables relationship-based access control evaluation.
	// Defaults to true.
	EnableReBAC *bool `json:"enable_rebac,omitempty"`

	// EnableCheckLog enables writing authorization check results to the
	// check log store. Defaults to true.
	EnableCheckLog *bool `json:"enable_check_log,omitempty"`
}

Config holds configuration for the Warden engine.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config with sensible defaults.

type Decision

type Decision string

Decision is the authorization outcome.

const (
	// DecisionAllow means the request is permitted.
	DecisionAllow Decision = "allow"

	// DecisionDeny means the request is denied (generic).
	DecisionDeny Decision = "deny"

	// DecisionDenyExplicit means an explicit deny policy matched.
	DecisionDenyExplicit Decision = "deny_explicit"

	// DecisionDenyDefault means no matching allow rule was found.
	DecisionDenyDefault Decision = "deny_default"

	// DecisionDenyNoRoles means the subject has no roles assigned.
	DecisionDenyNoRoles Decision = "deny_no_roles"

	// DecisionDenyNoPerms means no role grants the required permission.
	DecisionDenyNoPerms Decision = "deny_no_perms"

	// DecisionDenyCondition means an ABAC condition blocked the request.
	DecisionDenyCondition Decision = "deny_condition"

	// DecisionDenyRelation means no matching relation was found.
	DecisionDenyRelation Decision = "deny_relation"
)

type Engine

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

Engine is the central authorization engine. It coordinates RBAC, ReBAC, and ABAC evaluation, manages the store, and fires extension hooks.

func NewEngine

func NewEngine(opts ...Option) (*Engine, error)

NewEngine creates a new Warden engine with the given options.

func (*Engine) CanI

func (e *Engine) CanI(ctx context.Context, subjectKind SubjectKind, subjectID, action, resourceType, resourceID string, opts ...CallOption) (bool, error)

CanI is a shorthand for a simple authorization check. Optional CallOption values override scope for this single call.

func (*Engine) Check

func (e *Engine) Check(ctx context.Context, req *CheckRequest, opts ...CallOption) (*CheckResult, error)

Check performs an authorization check. This is the hot path. Optional CallOption values override scope for this single call.

func (*Engine) Config

func (e *Engine) Config() Config

Config returns the engine configuration.

func (*Engine) Enforce

func (e *Engine) Enforce(ctx context.Context, req *CheckRequest, opts ...CallOption) error

Enforce returns an error if the authorization check is denied. Optional CallOption values override scope for this single call.

func (*Engine) Health

func (e *Engine) Health(ctx context.Context) error

Health checks the health of the engine by pinging its store.

func (*Engine) Plugins

func (e *Engine) Plugins() *plugin.Registry

Plugins returns the plugin registry (may be nil).

func (*Engine) SetExpressionEvaluator

func (e *Engine) SetExpressionEvaluator(ev ExpressionEvaluator)

SetExpressionEvaluator overrides the resource-type expression evaluator at runtime. Used by the extension to wire dsl.NewEngineEvaluator after engine construction, since the evaluator depends on the engine's store.

func (*Engine) Start

func (e *Engine) Start(_ context.Context) error

Start performs any startup initialization.

func (*Engine) Stop

func (e *Engine) Stop(_ context.Context) error

Stop performs graceful shutdown.

func (*Engine) Store

func (e *Engine) Store() store.Store

Store returns the underlying composite store.

type Evaluator

type Evaluator interface {
	Evaluate(ctx context.Context, policies []*policy.Policy, req *CheckRequest) (*CheckResult, error)
}

Evaluator evaluates ABAC/PBAC policies against a check request.

func DefaultEvaluator

func DefaultEvaluator() Evaluator

DefaultEvaluator returns the built-in condition evaluator backed by the system wall clock.

func NewConditionEvaluator

func NewConditionEvaluator(now func() time.Time) Evaluator

NewConditionEvaluator returns an Evaluator that uses the supplied clock for PBAC time-window evaluation (NotBefore / NotAfter). Pass time.Now for production; tests can pass a fixed-time function.

type ExpressionEvaluator

type ExpressionEvaluator interface {
	EvalPermission(ctx context.Context, tenantID, namespacePath, resourceType, permName, subjectKind, subjectID, resourceID string) (matched bool, err error)
}

ExpressionEvaluator is an optional engine hook that evaluates resource-type permission expressions (the SpiceDB-style `viewer or editor or parent->read` expressions stored on ResourceType.Permissions[].Expression).

The DSL package implements this; wire it via WithExpressionEvaluator. When nil, resource-type expressions are inert (the relation graph walker still handles direct + transitive relations).

type GraphWalker

type GraphWalker interface {
	Walk(ctx context.Context, relStore relation.Store, tenantID, namespacePath string, req *CheckRequest) (allowed bool, path string, err error)
}

GraphWalker traverses the relation graph for ReBAC evaluation.

Walk is invoked with the namespace path of the request. Relations cascade like roles and policies: the walker follows tuples in the request namespace and every ancestor namespace (see AncestorNamespaces), so a relationship granted at a parent namespace is honored for descendant-scoped checks.

func DefaultGraphWalker

func DefaultGraphWalker(maxDepth int) GraphWalker

DefaultGraphWalker returns a BFS graph walker with the given max depth.

type ID

type ID = id.ID

ID is the primary identifier type for all Warden entities.

type MatchInfo

type MatchInfo struct {
	Source string `json:"source"` // "rbac", "abac", "rebac"
	RuleID string `json:"rule_id,omitempty"`
	Detail string `json:"detail,omitempty"`
}

MatchInfo describes what rule matched during evaluation.

type Option

type Option func(*Engine)

Option is a functional option for the Engine.

func WithCache

func WithCache(c Cache) Option

WithCache sets the check result cache.

func WithConfig

func WithConfig(c Config) Option

WithConfig sets the engine configuration.

func WithEvaluator

func WithEvaluator(ev Evaluator) Option

WithEvaluator sets the ABAC policy evaluator.

func WithExpressionEvaluator

func WithExpressionEvaluator(ev ExpressionEvaluator) Option

WithExpressionEvaluator sets the resource-type permission expression evaluator. The DSL package's NewEngineEvaluator is the canonical implementation. When unset, resource-type expressions are inert.

func WithGraphWalker

func WithGraphWalker(gw GraphWalker) Option

WithGraphWalker sets the ReBAC graph walker.

func WithLogger

func WithLogger(l log.Logger) Option

WithLogger sets the structured logger.

func WithPlugin

func WithPlugin(x plugin.Plugin) Option

WithPlugin registers a plugin with the engine.

func WithStore

func WithStore(s store.Store) Option

WithStore sets the composite store.

type Prefix

type Prefix = id.Prefix

Prefix identifies the entity type encoded in a TypeID.

type Resource

type Resource struct {
	Type       string         `json:"type"`
	ID         string         `json:"id"`
	Attributes map[string]any `json:"attributes,omitempty"`
}

Resource represents the target of an authorization check.

type Subject

type Subject struct {
	Kind       SubjectKind    `json:"kind"`
	ID         string         `json:"id"`
	Attributes map[string]any `json:"attributes,omitempty"`
}

Subject represents an actor in an authorization check.

type SubjectKind

type SubjectKind string

SubjectKind identifies the type of actor making an authorization request.

const (
	// SubjectUser represents a human user.
	SubjectUser SubjectKind = "user"

	// SubjectAPIKey represents an API key (e.g., from Keysmith).
	SubjectAPIKey SubjectKind = "api_key"

	// SubjectService represents a service-to-service caller.
	SubjectService SubjectKind = "service"

	// SubjectServiceAcct represents a service account.
	SubjectServiceAcct SubjectKind = "service_acct"
)

Directories

Path Synopsis
_examples
abac command
Example: attribute-based access control with conditions.
Example: attribute-based access control with conditions.
forge command
Example: Warden as a Forge extension with API routes.
Example: Warden as a Forge extension with API routes.
rbac command
Example: pure RBAC with role inheritance.
Example: pure RBAC with role inheritance.
rebac command
Example: Zanzibar-style ReBAC with transitive relations.
Example: Zanzibar-style ReBAC with transitive relations.
standalone command
Example: standalone Warden usage without Forge.
Example: standalone Warden usage without Forge.
standalone-embed command
Standalone-embed example — boots a Warden engine, applies an embedded .warden config tree, then runs a sample Check.
Standalone-embed example — boots a Warden engine, applies an embedded .warden config tree, then runs a sample Check.
Package api provides HTTP handlers for the Warden authorization engine.
Package api provides HTTP handlers for the Warden authorization engine.
Package assignment defines the Assignment entity (role→subject binding).
Package assignment defines the Assignment entity (role→subject binding).
Package cache provides caching implementations for Warden check results.
Package cache provides caching implementations for Warden check results.
Package checklog defines the check audit log Entry entity.
Package checklog defines the check audit log Entry entity.
cmd
internal/cli
Package cli holds shared helpers for the warden CLI binaries.
Package cli holds shared helpers for the warden CLI binaries.
warden command
Command warden is the CLI for the .warden DSL.
Command warden is the CLI for the .warden DSL.
warden-lsp command
Command warden-lsp is a Language Server Protocol (LSP) server for the `.warden` DSL.
Command warden-lsp is a Language Server Protocol (LSP) server for the `.warden` DSL.
components
templ: version: v0.3.1001
templ: version: v0.3.1001
pages
templ: version: v0.3.1001
templ: version: v0.3.1001
settings
templ: version: v0.3.1001
templ: version: v0.3.1001
widgets
templ: version: v0.3.1001
templ: version: v0.3.1001
Package dsl implements the .warden declarative configuration language.
Package dsl implements the .warden declarative configuration language.
Package extension provides a Forge extension entry point for Warden.
Package extension provides a Forge extension entry point for Warden.
Package id defines TypeID-based identity types for all Warden entities.
Package id defines TypeID-based identity types for all Warden entities.
Package lsp implements the Warden Language Server Protocol server for the .warden DSL.
Package lsp implements the Warden Language Server Protocol server for the .warden DSL.
Package middleware provides HTTP authorization middleware for Warden.
Package middleware provides HTTP authorization middleware for Warden.
Package permission defines the Permission entity and its store interface.
Package permission defines the Permission entity and its store interface.
Package plugin defines the plugin system for Warden.
Package plugin defines the plugin system for Warden.
Package policy defines the Policy entity used for ABAC and PBAC evaluation.
Package policy defines the Policy entity used for ABAC and PBAC evaluation.
Package relation defines the Tuple entity for ReBAC (Zanzibar-style relations).
Package relation defines the Tuple entity for ReBAC (Zanzibar-style relations).
Package resourcetype defines the ResourceType entity for ReBAC schema definitions.
Package resourcetype defines the ResourceType entity for ReBAC schema definitions.
Package role defines the Role entity and its store interface for RBAC.
Package role defines the Role entity and its store interface for RBAC.
Package store defines the aggregate persistence interface.
Package store defines the aggregate persistence interface.
contract
Package contract provides shared test contracts that every Warden store backend must satisfy.
Package contract provides shared test contracts that every Warden store backend must satisfy.
memory
Package memory provides an in-memory implementation of the Warden composite store.
Package memory provides an in-memory implementation of the Warden composite store.
mongo
Package mongo provides a MongoDB Store implementation for the Warden store.
Package mongo provides a MongoDB Store implementation for the Warden store.
postgres
Package postgres provides a PostgreSQL implementation of the Warden composite store using grove ORM with Go-based migrations.
Package postgres provides a PostgreSQL implementation of the Warden composite store using grove ORM with Go-based migrations.
sqlite
Package sqlite provides a SQLite Store implementation for embedded/edge use.
Package sqlite provides a SQLite Store implementation for embedded/edge use.
Package wardenerr holds shared sentinel errors used across warden subpackages.
Package wardenerr holds shared sentinel errors used across warden subpackages.

Jump to

Keyboard shortcuts

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