Composable RBAC, ABAC & ReBAC for Go

Guard your access

Role-based, attribute-based, and relationship-based authorization unified behind a single Check API — tenant-scoped, plugin-extensible, and composable.

$go get github.com/xraph/warden
Subject
Check
Decision
RBAC
ABAC
ReBAC
role.check
allowed
policy.eval
no opinion
graph.walk
path found
RBAC
ABAC
ReBAC
TypeID
Features

Everything you need for authorization

Warden handles the hard parts — role hierarchies, policy evaluation, graph traversal, and decision merging — so you can focus on your application.

Role-Based Access Control

Hierarchical roles with permissions, resource-scoped assignments, and glob-based permission matching. The most common authorization model.

rbac.go
"text-fd-muted-foreground/60 italic">// Create role with permissions
r := &role.Role{ID: id.NewRoleID(), Name: "Editor", Slug: "editor"}
store.CreateRole(ctx, r)
store.AttachPermission(ctx, r.ID, permID)
 
"text-fd-muted-foreground/60 italic">// Assign to user
store.CreateAssignment(ctx, &assignment.Assignment{
RoleID: r.ID, SubjectKind: "user", SubjectID: "user-42",
})

Attribute-Based Policies

Define deny/allow policies with conditions on IP ranges, time windows, departments, and custom attributes. Conditions support 12+ operators.

abac.go
p := &policy.Policy{
Name: "Office Hours Only",
Effect: policy.EffectDeny,
Actions: []string{"write", "delete"},
Conditions: []policy.Condition{{
Field: "time", Operator: policy.OpTimeAfter,
Value: "18:00",
}},
IsActive: true,
}

Relationship-Based (ReBAC)

Google Zanzibar-inspired relation tuples with BFS graph traversal. Model document sharing, team membership, and org hierarchies.

rebac.go
"text-fd-muted-foreground/60 italic">// user:42 is viewer of document:123
store.CreateRelation(ctx, &relation.Tuple{
ObjectType: "document", ObjectID: "doc-123",
Relation: "viewer",
SubjectType: "user", SubjectID: "user-42",
})
"text-fd-muted-foreground/60 italic">// Transitive: user → team → project

Unified Check API

A single Check() call evaluates RBAC, ABAC, and ReBAC together. Explicit deny beats allow, which beats default deny.

check.go
result, _ := eng.Check(ctx, &warden.CheckRequest{
Subject: warden.Subject{Kind: "user", ID: "user-42"},
Action: "read",
ResourceType: "document",
ResourceID: "doc-123",
Context: map[string]any{"ip": "10.0.1.5"},
})
"text-fd-muted-foreground/60 italic">// result.Allowed, result.Reason, result.Sources

Multi-Tenant Isolation

Every operation is scoped to a tenant via context. Cross-tenant access is structurally impossible at the store layer.

tenancy.go
"text-fd-muted-foreground/60 italic">// With Forge(automatic)
ctx = forge.WithScope(ctx, forge.Scope{
AppID: "myapp", TenantID: "tenant-123",
})
 
"text-fd-muted-foreground/60 italic">// Standalone
ctx = warden.WithTenant(ctx, "myapp", "tenant-123")
"text-fd-muted-foreground/60 italic">// All operations scoped automatically

Plugin System

Register plugins that implement lifecycle hooks for audit logging, metrics, and custom behavior. Auto-discovered via type assertion.

plugins.go
eng, _ := warden.NewEngine(
warden.WithStore(store),
warden.WithPlugin(audit_hook.New(chronicle)),
warden.WithPlugin(observability.New()),
)
"text-fd-muted-foreground/60 italic">// Hooks: BeforeCheck, AfterCheck, RoleCreated,
"text-fd-muted-foreground/60 italic">// PolicyUpdated, RelationWritten, ...
Authorization Pipeline

From request to decision.

Warden orchestrates the entire authorization lifecycle — RBAC evaluation, ABAC policy matching, ReBAC graph traversal, and decision merging.

Three Models, One Check

RBAC, ABAC, and ReBAC are evaluated in parallel and their decisions merged with deny-overrides priority. A single Check() call handles everything.

BFS Graph Traversal

ReBAC uses breadth-first search with cycle detection and configurable max depth to traverse relation graphs and find transitive permissions.

Audit Trail & Metrics

Every check is logged with subject, action, resource, decision, and duration. Wire in Chronicle for audit events or Prometheus for metrics via the plugin system.

Request
authz.check
Evaluate3 models
Mergedecision
rbac.matched
Allowed
abac.evaluated
Evaluating
rebac.traversed
Path Found
Allowed
Evaluating
No Opinion
Denied
Developer Experience

Simple API. Powerful primitives.

Set up role-based access or traverse a relationship graph in under 30 lines. Warden handles evaluation, merging, and audit logging.

RBAC
rbac.go
1package main
2 
3import (
4 "context"
5 "fmt"
6 "time"
7 
8 "github.com/xraph/warden"
9 "github.com/xraph/warden/assignment"
10 "github.com/xraph/warden/id"
11 "github.com/xraph/warden/permission"
12 "github.com/xraph/warden/role"
13 "github.com/xraph/warden/store/memory"
14)
15 
16func main() {
17 ctx := context.Background()
18 st := memory.New()
19 eng, _ := warden.NewEngine(warden.WithStore(st))
20 
21 now := time.Now()
22 perm := &permission.Permission{
23 ID: id.NewPermissionID(), Resource: "document",
24 Action: "read", Name: "Read Docs",
25 CreatedAt: now, UpdatedAt: now,
26 }
27 r := &role.Role{
28 ID: id.NewRoleID(), Name: "Viewer", Slug: "viewer",
29 CreatedAt: now, UpdatedAt: now,
30 }
31 _ = st.CreatePermission(ctx, perm)
32 _ = st.CreateRole(ctx, r)
33 _ = st.AttachPermission(ctx, r.ID, perm.ID)
34 _ = st.CreateAssignment(ctx, &assignment.Assignment{
35 ID: id.NewAssignmentID(), RoleID: r.ID,
36 SubjectKind: "user", SubjectID: "alice",
37 CreatedAt: now,
38 })
39 
40 result, _ := eng.Check(ctx, &warden.CheckRequest{
41 Subject: warden.Subject{Kind: "user", ID: "alice"},
42 Action: "read",
43 ResourceType: "document",
44 })
45 fmt.Printf("allowed=%v reason=%q\n",
46 result.Allowed, result.Reason)
47 "text-fd-muted-foreground/60 italic">// allowed=true reason="rbac: granted"
48}
ReBAC
rebac.go
1package main
2 
3import (
4 "context"
5 "fmt"
6 "time"
7 
8 "github.com/xraph/warden"
9 "github.com/xraph/warden/id"
10 "github.com/xraph/warden/relation"
11 "github.com/xraph/warden/store/memory"
12)
13 
14func main() {
15 ctx := context.Background()
16 st := memory.New()
17 eng, _ := warden.NewEngine(warden.WithStore(st))
18 
19 now := time.Now()
20 
21 "text-fd-muted-foreground/60 italic">// user:alice is member of team:eng
22 _ = st.CreateRelation(ctx, &relation.Tuple{
23 ID: id.NewRelationID(),
24 ObjectType: "team", ObjectID: "eng",
25 Relation: "member",
26 SubjectType: "user", SubjectID: "alice",
27 CreatedAt: now,
28 })
29 
30 "text-fd-muted-foreground/60 italic">// team:eng is editor of project:alpha
31 _ = st.CreateRelation(ctx, &relation.Tuple{
32 ID: id.NewRelationID(),
33 ObjectType: "project", ObjectID: "alpha",
34 Relation: "editor",
35 SubjectType: "team", SubjectID: "eng",
36 CreatedAt: now,
37 })
38 
39 "text-fd-muted-foreground/60 italic">// Can alice edit project:alpha?
40 "text-fd-muted-foreground/60 italic">// Traverses: alice → team:eng → project:alpha
41 result, _ := eng.Check(ctx, &warden.CheckRequest{
42 Subject: warden.Subject{Kind: "user", ID: "alice"},
43 Action: "write",
44 ResourceType: "project",
45 ResourceID: "alpha",
46 })
47 fmt.Printf("allowed=%v\n", result.Allowed)
48 "text-fd-muted-foreground/60 italic">// allowed=true (via transitive relation)
49}

Start building with Warden

Add RBAC, ABAC, and ReBAC authorization to your Go service in minutes. Warden handles role hierarchies, policy evaluation, graph traversal, and audit trails out of the box.

$go get github.com/xraph/warden