Warden

Resource Types

Define valid relations and permissions for resource types.

Overview

Resource types define the schema for your authorization model. They declare which relations and permissions are valid for each type of object.

Every config example on this page comes in two flavours: Go (programmatic — call the store directly) and DSL (declarative — write .warden source and apply it via warden apply or dsl.ApplyFS). They produce identical state.

ResourceType Fields

FieldTypeDescription
IDid.ResourceTypeIDTypeID (rtype_...) — auto-assigned on Create when unset
NamestringResource type name (e.g., "document")
DescriptionstringHuman-readable description
Relations[]RelationDefValid relations for this type
Permissions[]PermissionDefDerived permission expressions

Defining Relations

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

// IDs and CreatedAt/UpdatedAt timestamps are auto-assigned by the
// store on Create — set them only when you need a specific value.
docType := &resourcetype.ResourceType{
    Name:        "document",
    Description: "A document resource",
    Relations: []resourcetype.RelationDef{
        {Name: "owner",  AllowedSubjects: []string{"user"}},
        {Name: "editor", AllowedSubjects: []string{"user", "team#member"}},
        {Name: "viewer", AllowedSubjects: []string{"user", "team#member", "group#member"}},
        {Name: "parent", AllowedSubjects: []string{"folder"}},
    },
    Permissions: []resourcetype.PermissionDef{
        {Name: "read",   Expression: "viewer or editor or owner or parent->read"},
        {Name: "write",  Expression: "editor or owner or parent->write"},
        {Name: "delete", Expression: "owner"},
    },
}
err := store.CreateResourceType(ctx, docType)
// docType.ID is now populated.
warden config 1
tenant t1

resource document {
  description = "A document resource"

  relation owner:  user
  relation editor: user | team#member
  relation viewer: user | team#member | group#member
  relation parent: folder

  permission read   = viewer or editor or owner or parent->read
  permission write  = editor or owner or parent->write
  permission delete = owner
}

The expression algebra (or, and, not, ->) is the same as the Go form — Expression strings parse with the same grammar. See the language reference for precedence rules and traversal semantics.

RelationDef

FieldTypeDescription
NamestringRelation name (e.g., "viewer")
AllowedSubjects[]stringAllowed subject types — bare types (user) or subject sets (group#member)

PermissionDef

FieldTypeDescription
NamestringPermission name (e.g., "read")
ExpressionstringBoolean expression over relations (e.g., "viewer or editor or owner")

Example: Google Drive-like Model

// Folder type
folderType := &resourcetype.ResourceType{
    Name: "folder",
    Relations: []resourcetype.RelationDef{
        {Name: "owner",  AllowedSubjects: []string{"user"}},
        {Name: "editor", AllowedSubjects: []string{"user", "group#member"}},
        {Name: "viewer", AllowedSubjects: []string{"user", "group#member"}},
    },
    Permissions: []resourcetype.PermissionDef{
        {Name: "read",  Expression: "viewer or editor or owner"},
        {Name: "write", Expression: "editor or owner"},
        {Name: "share", Expression: "owner"},
    },
}

// Document type — `parent->read` traverses the parent relation and
// re-checks read on the resulting folder.
docType := &resourcetype.ResourceType{
    Name: "document",
    Relations: []resourcetype.RelationDef{
        {Name: "owner",  AllowedSubjects: []string{"user"}},
        {Name: "editor", AllowedSubjects: []string{"user", "group#member"}},
        {Name: "viewer", AllowedSubjects: []string{"user", "group#member"}},
        {Name: "parent", AllowedSubjects: []string{"folder"}},
    },
    Permissions: []resourcetype.PermissionDef{
        {Name: "read",   Expression: "viewer or editor or owner or parent->read"},
        {Name: "write",  Expression: "editor or owner or parent->write"},
        {Name: "delete", Expression: "owner"},
    },
}
warden config 1
tenant t1

// Folder type
resource folder {
  relation owner:  user
  relation editor: user | group#member
  relation viewer: user | group#member

  permission read  = viewer or editor or owner
  permission write = editor or owner
  permission share = owner
}

// Document type — `parent->read` traverses the parent relation and
// re-checks read on the resulting folder.
resource document {
  relation owner:  user
  relation editor: user | group#member
  relation viewer: user | group#member
  relation parent: folder

  permission read   = viewer or editor or owner or parent->read
  permission write  = editor or owner or parent->write
  permission delete = owner
}

CRUD Operations

These are runtime API calls — they don't have a DSL equivalent because the DSL is declarative (you describe the desired end state, not the operation). The applier picks the right CRUD call internally.

// Create
store.CreateResourceType(ctx, rt)

// Get by ID
rt, _ := store.GetResourceType(ctx, rtID)

// Get by name
rt, _ := store.GetResourceTypeByName(ctx, tenantID, "document")

// List
types, _ := store.ListResourceTypes(ctx, &resourcetype.ListFilter{
    TenantID: "t1",
    Limit:    50,
})

// Update
store.UpdateResourceType(ctx, rt)

// Delete
store.DeleteResourceType(ctx, rtID)

On this page