Full Example
A complete example combining RBAC, ABAC, and ReBAC in a single application.
This example demonstrates all three authorization models working together.
Setup
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/xraph/warden"
"github.com/xraph/warden/assignment"
"github.com/xraph/warden/id"
"github.com/xraph/warden/permission"
"github.com/xraph/warden/policy"
"github.com/xraph/warden/relation"
"github.com/xraph/warden/role"
"github.com/xraph/warden/store/memory"
)
func main() {
ctx := context.Background()
st := memory.New()
eng, err := warden.NewEngine(warden.WithStore(st))
if err != nil {
log.Fatal(err)
}Step 1: RBAC — Roles and Permissions
// IDs and CreatedAt/UpdatedAt timestamps are auto-assigned by the
// store on Create — no boilerplate. The pointer is mutated in
// place, so role.ID is populated by the time the call returns.
// Create permissions
readPerm := &permission.Permission{
Name: "doc:read", Resource: "document", Action: "read",
}
writePerm := &permission.Permission{
Name: "doc:write", Resource: "document", Action: "write",
}
_ = st.CreatePermission(ctx, readPerm)
_ = st.CreatePermission(ctx, writePerm)
// Create roles
viewerRole := &role.Role{Name: "Viewer", Slug: "viewer"}
editorRole := &role.Role{Name: "Editor", Slug: "editor"}
_ = st.CreateRole(ctx, viewerRole)
_ = st.CreateRole(ctx, editorRole)
// Attach permissions by name (not typeid).
_ = st.AttachPermission(ctx, viewerRole.ID, permission.Ref{Name: "doc:read"})
_ = st.AttachPermission(ctx, editorRole.ID, permission.Ref{Name: "doc:read"})
_ = st.AttachPermission(ctx, editorRole.ID, permission.Ref{Name: "doc:write"})
// Assign viewer role to user
_ = st.CreateAssignment(ctx, &assignment.Assignment{
RoleID: viewerRole.ID,
SubjectKind: "user",
SubjectID: "alice",
})Step 2: ABAC — Policy Guardrails
// Deny writes after business hours
_ = st.CreatePolicy(ctx, &policy.Policy{
Name: "Business Hours Only",
Effect: policy.EffectDeny,
Priority: 10,
IsActive: true,
Version: 1,
Subjects: []string{"*"},
Actions: []string{"write", "delete"},
Resources: []string{"*"},
Conditions: []policy.Condition{{
Field: "time",
Operator: policy.OpTimeAfter,
Value: "18:00",
}},
})Step 3: ReBAC — Relationship-Based Sharing
// Bob can view doc-456 via direct relation
_ = st.CreateRelation(ctx, &relation.Tuple{
ObjectType: "document",
ObjectID: "doc-456",
Relation: "viewer",
SubjectType: "user",
SubjectID: "bob",
})Step 4: Run Checks
checks := []struct {
name string
req *warden.CheckRequest
}{
{
name: "Alice reads document (RBAC)",
req: &warden.CheckRequest{
Subject: warden.Subject{Kind: "user", ID: "alice"},
Action: "read",
ResourceType: "document",
ResourceID: "doc-123",
},
},
{
name: "Alice writes document (RBAC - should fail, viewer only)",
req: &warden.CheckRequest{
Subject: warden.Subject{Kind: "user", ID: "alice"},
Action: "write",
ResourceType: "document",
ResourceID: "doc-123",
},
},
{
name: "Bob views doc-456 (ReBAC)",
req: &warden.CheckRequest{
Subject: warden.Subject{Kind: "user", ID: "bob"},
Action: "read",
ResourceType: "document",
ResourceID: "doc-456",
},
},
}
for _, c := range checks {
result, err := eng.Check(ctx, c.req)
if err != nil {
fmt.Printf("%-50s ERROR: %v\n", c.name, err)
continue
}
fmt.Printf("%-50s allowed=%v reason=%q\n", c.name, result.Allowed, result.Reason)
}
}Expected Output
Alice reads document (RBAC) allowed=true reason="rbac: granted"
Alice writes document (RBAC - should fail) allowed=false reason="default deny"
Bob views doc-456 (ReBAC) allowed=true reason="rebac: granted"