{"id":47699336,"url":"https://github.com/xraph/warden","last_synced_at":"2026-04-02T17:03:11.369Z","repository":{"id":339627827,"uuid":"1162667158","full_name":"xraph/warden","owner":"xraph","description":"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.","archived":false,"fork":false,"pushed_at":"2026-03-28T20:54:20.000Z","size":411,"stargazers_count":1,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-28T22:25:53.490Z","etag":null,"topics":["authz","permissions"],"latest_commit_sha":null,"homepage":"https://warden.xraph.com","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xraph.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-20T14:48:20.000Z","updated_at":"2026-03-28T20:54:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/xraph/warden","commit_stats":null,"previous_names":["xraph/warden"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/xraph/warden","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xraph%2Fwarden","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xraph%2Fwarden/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xraph%2Fwarden/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xraph%2Fwarden/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xraph","download_url":"https://codeload.github.com/xraph/warden/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xraph%2Fwarden/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31311027,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authz","permissions"],"created_at":"2026-04-02T17:02:17.923Z","updated_at":"2026-04-02T17:03:11.358Z","avatar_url":"https://github.com/xraph.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Warden — Composable permissions \u0026 authorization engine\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/xraph/warden.svg)](https://pkg.go.dev/github.com/xraph/warden)\n[![Go Version](https://img.shields.io/badge/go-1.24+-blue)](https://go.dev)\n[![CI](https://github.com/xraph/warden/actions/workflows/ci.yml/badge.svg)](https://github.com/xraph/warden/actions/workflows/ci.yml)\n\nWarden 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.\n\n## Features\n\n- **RBAC** — Roles, permissions, role inheritance, resource-scoped assignments\n- **ABAC** — Attribute-based policies with conditions (IP ranges, time windows, regex, etc.)\n- **ReBAC** — Zanzibar-style relation tuples with BFS graph walking\n- **Multi-model** — Use RBAC, ABAC, and ReBAC together; explicit deny \u003e allow \u003e default deny\n- **Multi-tenant** — All data is tenant-scoped via `forge.Scope` or standalone context helpers\n- **Extensible** — Plugin hooks for audit logging, metrics, and custom lifecycle events\n- **Caching** — Built-in in-memory LRU cache with TTL and per-tenant/subject invalidation\n- **Forge native** — Drop-in Forge extension with DI, API routes, and middleware\n\n## Quick Start\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n\n    \"github.com/xraph/warden\"\n    \"github.com/xraph/warden/assignment\"\n    \"github.com/xraph/warden/id\"\n    \"github.com/xraph/warden/permission\"\n    \"github.com/xraph/warden/role\"\n    \"github.com/xraph/warden/store/memory\"\n)\n\nfunc main() {\n    ctx := warden.WithTenant(context.Background(), \"myapp\", \"tenant-1\")\n    s := memory.New()\n\n    eng, err := warden.NewEngine(warden.WithStore(s))\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    // Create role + permission.\n    roleID := id.NewRoleID()\n    permID := id.NewPermissionID()\n    _ = s.CreateRole(ctx, \u0026role.Role{ID: roleID, TenantID: \"tenant-1\", Name: \"editor\", Slug: \"editor\"})\n    _ = s.CreatePermission(ctx, \u0026permission.Permission{ID: permID, TenantID: \"tenant-1\", Name: \"doc:read\", Resource: \"doc\", Action: \"read\"})\n    _ = s.AttachPermission(ctx, roleID, permID)\n\n    // Assign role to user.\n    _ = s.CreateAssignment(ctx, \u0026assignment.Assignment{\n        ID: id.NewAssignmentID(), TenantID: \"tenant-1\",\n        RoleID: roleID, SubjectKind: \"user\", SubjectID: \"alice\",\n    })\n\n    // Check authorization.\n    result, err := eng.Check(ctx, \u0026warden.CheckRequest{\n        Subject:  warden.Subject{Kind: warden.SubjectUser, ID: \"alice\"},\n        Action:   warden.Action{Name: \"read\"},\n        Resource: warden.Resource{Type: \"doc\", ID: \"d1\"},\n    })\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Allowed: %v\\n\", result.Allowed) // true\n}\n```\n\n## Installation\n\n```bash\ngo get github.com/xraph/warden\n```\n\n## Architecture\n\n```\nCheck Request\n     |\n     v\n+----------+     +---------+     +---------+\n|   RBAC   | --\u003e |  ReBAC  | --\u003e |  ABAC   |\n| roles \u0026  |     | relation|     | policy  |\n| perms    |     | tuples  |     | engine  |\n+----------+     +---------+     +---------+\n     |                |               |\n     +-------+--------+-------+------+\n             |                 |\n       mergeDecisions    explicit deny\n             |            \u003e allow\n             v            \u003e default deny\n       CheckResult\n```\n\nThe engine evaluates all three models and merges results:\n1. **Explicit deny** (from ABAC) always wins\n2. **Any allow** from any model grants access\n3. **Default deny** if no rules match\n\n## Authorization Models\n\n### RBAC (Role-Based Access Control)\n\nRoles contain permissions. Users are assigned roles (globally or scoped to specific resources). Roles support inheritance via parent chains.\n\n### ReBAC (Relationship-Based Access Control)\n\nZanzibar-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).\n\n### ABAC (Attribute-Based Access Control)\n\nPolicies 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.\n\n## Store Backends\n\nWarden ships with four pluggable store backends. All implement the composite `Store` interface from `store/store.go`.\n\n| Backend | Package | Use case |\n| --- | --- | --- |\n| Memory | `store/memory` | Testing, development |\n| PostgreSQL | `store/postgres` | Production (Grove ORM, migrations, transactions) |\n| SQLite | `store/sqlite` | Embedded / edge deployments (Grove ORM) |\n| MongoDB | `store/mongo` | NoSQL / document-oriented workloads (BSON, compound indexes) |\n\n```go\nimport \"github.com/xraph/warden/store/memory\"\nimport \"github.com/xraph/warden/store/postgres\"\nimport \"github.com/xraph/warden/store/sqlite\"\nimport \"github.com/xraph/warden/store/mongo\"\n\n// Memory (no config needed)\ns := memory.New()\n\n// PostgreSQL / SQLite — pass a Grove database instance\ns := postgres.New(groveDB)\n\n// MongoDB — pass a Grove MongoDB instance\ns := mongo.New(mongoDB)\n\n// All stores support Migrate() for schema setup\n_ = s.Migrate(ctx)\n```\n\n## Plugin System\n\nWarden 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.\n\n```go\nimport \"github.com/xraph/warden/plugin\"\n\ntype AuditPlugin struct{}\n\nfunc (p *AuditPlugin) Name() string { return \"audit\" }\n\n// Opt in to the hooks you care about:\nfunc (p *AuditPlugin) RoleCreated(ctx context.Context, r *role.Role) error {\n    log.Printf(\"role created: %s\", r.Name)\n    return nil\n}\nfunc (p *AuditPlugin) AfterCheck(ctx context.Context, req, result any) error {\n    log.Printf(\"check completed\")\n    return nil\n}\n```\n\n### Available Hooks\n\n| Category | Hook | Trigger |\n| --- | --- | --- |\n| Check | `BeforeCheck(ctx, req)` | Before authorization evaluation |\n| Check | `AfterCheck(ctx, req, result)` | After authorization evaluation |\n| Roles | `RoleCreated(ctx, role)` | Role created |\n| Roles | `RoleUpdated(ctx, role)` | Role modified |\n| Roles | `RoleDeleted(ctx, roleID)` | Role removed |\n| Permissions | `PermissionCreated(ctx, perm)` | Permission created |\n| Permissions | `PermissionDeleted(ctx, permID)` | Permission removed |\n| Permissions | `PermissionAttached(ctx, roleID, permID)` | Permission attached to role |\n| Permissions | `PermissionDetached(ctx, roleID, permID)` | Permission detached from role |\n| Assignments | `RoleAssigned(ctx, assignment)` | Role assigned to subject |\n| Assignments | `RoleUnassigned(ctx, assignment)` | Role unassigned from subject |\n| Relations | `RelationWritten(ctx, tuple)` | Relation tuple created |\n| Relations | `RelationDeleted(ctx, relID)` | Relation tuple removed |\n| Policies | `PolicyCreated(ctx, policy)` | ABAC policy created |\n| Policies | `PolicyUpdated(ctx, policy)` | ABAC policy modified |\n| Policies | `PolicyDeleted(ctx, polID)` | ABAC policy removed |\n| Lifecycle | `Shutdown(ctx)` | Engine shutting down |\n\nHook errors are logged as warnings but never block the caller.\n\n## Caching\n\nWarden includes a built-in in-memory LRU cache for `Check()` results with TTL-based expiration and scoped invalidation.\n\n```go\nimport \"github.com/xraph/warden/cache\"\n\nc := cache.NewMemory(\n    cache.WithTTL(5 * time.Minute),   // Default: 5m\n    cache.WithMaxSize(10000),          // Default: 10,000 entries\n)\n\neng, _ := warden.NewEngine(\n    warden.WithStore(s),\n    warden.WithCache(c),\n)\n```\n\nCache keys are scoped by `tenantID:subjectKind:subjectID:action:resourceType:resourceID`.\n\n### Invalidation\n\n```go\n// Invalidate all cached results for a tenant.\nc.InvalidateTenant(ctx, \"tenant-1\")\n\n// Invalidate all cached results for a specific subject.\nc.InvalidateSubject(ctx, \"tenant-1\", warden.SubjectUser, \"alice\")\n```\n\nThe cache automatically invalidates when roles, permissions, or assignments are modified through the engine.\n\n## Middleware\n\nWarden provides HTTP middleware for Forge route protection.\n\n```go\nimport wardenmw \"github.com/xraph/warden/middleware\"\n\n// Require a single permission — returns 403 if denied.\nrouter.GET(\"/documents/:id\", handler,\n    forge.WithMiddleware(wardenmw.Require(eng, \"read\", \"document\")),\n)\n\n// RequireAny — allows if ANY check passes (OR logic).\nrouter.POST(\"/admin/action\", handler,\n    forge.WithMiddleware(wardenmw.RequireAny(eng,\n        warden.CheckRequest{Action: warden.Action{Name: \"admin\"}, Resource: warden.Resource{Type: \"system\"}},\n        warden.CheckRequest{Action: warden.Action{Name: \"write\"}, Resource: warden.Resource{Type: \"config\"}},\n    )),\n)\n\n// RequireAll — allows only if ALL checks pass (AND logic).\nrouter.DELETE(\"/documents/:id\", handler,\n    forge.WithMiddleware(wardenmw.RequireAll(eng,\n        warden.CheckRequest{Action: warden.Action{Name: \"delete\"}, Resource: warden.Resource{Type: \"document\"}},\n        warden.CheckRequest{Action: warden.Action{Name: \"admin\"}, Resource: warden.Resource{Type: \"document\"}},\n    )),\n)\n```\n\nSubject resolution priority:\n\n1. Authenticated user ID from `forge.UserIDFromContext()`\n2. Falls back to `unknown:anonymous`\n\n## Configuration\n\n```go\neng, err := warden.NewEngine(\n    warden.WithStore(store),                  // Required: store backend\n    warden.WithCache(cache),                  // Optional: check result cache\n    warden.WithConfig(warden.Config{\n        MaxGraphDepth: 10,                    // ReBAC graph traversal depth (default: 10)\n        CacheTTL:      5 * time.Minute,       // Check result cache TTL (0 = disabled)\n        EnableRBAC:    ptrBool(true),         // Enable RBAC evaluation (default: true)\n        EnableABAC:    ptrBool(true),         // Enable ABAC evaluation (default: true)\n        EnableReBAC:   ptrBool(true),         // Enable ReBAC evaluation (default: true)\n    }),\n    warden.WithPlugin(auditPlugin),           // Optional: lifecycle plugins\n    warden.WithEvaluator(customEvaluator),    // Optional: custom ABAC evaluator\n    warden.WithGraphWalker(customWalker),     // Optional: custom ReBAC graph walker\n    warden.WithLogger(logger),                // Optional: structured logger\n)\n```\n\n## ID System\n\nWarden uses **TypeID** — UUIDv7-based, K-sortable, URL-safe identifiers with type prefixes for all entities.\n\n```text\nrole_01h2xcejqtf2nbrexx3vqjhp41\nperm_01h2xcejqtf2nbrexx3vqjhp41\nasgn_01h2xcejqtf2nbrexx3vqjhp41\n```\n\n### Prefixes\n\n| Prefix | Entity | Constructor |\n| --- | --- | --- |\n| `role` | Role | `id.NewRoleID()` |\n| `perm` | Permission | `id.NewPermissionID()` |\n| `asgn` | Assignment | `id.NewAssignmentID()` |\n| `wpol` | Policy | `id.NewPolicyID()` |\n| `rel` | Relation | `id.NewRelationID()` |\n| `chklog` | Check log | `id.NewCheckLogID()` |\n| `rtype` | Resource type | `id.NewResourceTypeID()` |\n| `cond` | Condition | `id.NewConditionID()` |\n\n```go\nimport \"github.com/xraph/warden/id\"\n\n// Create\nroleID := id.NewRoleID()       // role_01h2xce...\npermID := id.NewPermissionID() // perm_01h2xce...\n\n// Parse\nparsed, err := id.ParseRoleID(\"role_01h2xcejqtf2nbrexx3vqjhp41\")\n\n// Check\nif roleID.IsNil() { /* zero-value */ }\n\n// Database support: SQL (Value/Scan), BSON (MarshalBSONValue/UnmarshalBSONValue)\n```\n\n## Forge Integration\n\n```go\nimport (\n    \"github.com/xraph/forge\"\n    wardenext \"github.com/xraph/warden/extension\"\n    wardenmw \"github.com/xraph/warden/middleware\"\n)\n\n// Register as Forge extension.\napp := forge.New(\n    forge.WithExtensions(\n        wardenext.New(\n            wardenext.WithStore(store),\n        ),\n    ),\n)\n\n// Use middleware for route protection.\nrouter.GET(\"/documents/:id\", handler,\n    forge.WithMiddleware(wardenmw.Require(eng, \"read\", \"document\")),\n)\n```\n\n## Examples\n\nSee the `_examples/` directory:\n\n- `_examples/standalone/` — Warden without Forge\n- `_examples/forge/` — Warden as Forge extension\n- `_examples/rbac/` — Pure RBAC with role inheritance\n- `_examples/rebac/` — Zanzibar-style ReBAC\n- `_examples/abac/` — Attribute-based policies\n\n## License\n\nPart of the Forge ecosystem.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxraph%2Fwarden","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxraph%2Fwarden","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxraph%2Fwarden/lists"}