Encodes roles, permissions, memberships, and adjacency edges for tenant-aware RBAC.

Fields it adds

FieldTypeRequiredDescription
role_catalog AuthzRoleDocument[] yes Canonical RBAC roles (R21.2 Part 4.2 TABLE 1).
permission_catalog AuthzPermissionDocument[] yes Atomic permissions following resource:action notation (TABLE 2).
role_permissions Record<string, string[]> yes Junction map for role→permission edges (TABLE 3).
membership_records AuthzMembershipDocument[] yes SaaS membership triple (user_id, organization_id, role_id) with UNIQUE constraint (TABLE 4).
role_hierarchy_edges AuthzRoleHierarchyEdge[] no Parent→child adjacency list for hierarchical RBAC (Part 3.1).
session_roles string[] no Materialized roles granted within the current session/token exchange.

What it shows in each context

list
RoleBadgeList
detail
MembershipPanel
form
RoleAssignmentForm

Parameters

defaultRoleId string
Role identifier applied when tenants are provisioned without an explicit role (R21.2 §2.3).
hierarchyDepthLimit number
Maximum recursion depth when traversing role hierarchies for derived permissions.

Objects that use it

The trait file

traits/core/Authable.trait.yaml
trait:
  name: Authable
  version: 1.0.0
  description: |
    Role-based access control extension pack grounded in the R21.2 membership pattern.
    Encodes roles, permissions, memberships, and adjacency edges for tenant-aware RBAC.
  category: core
  tags:
    - authorization
    - rbac
    - membership
    - saas
    - security

parameters:
  - name: defaultRoleId
    type: string
    required: false
    description: Role identifier applied when tenants are provisioned without an explicit role (R21.2 §2.3).
    validation:
      pattern: "^[0-9a-fA-F-]{32,36}$"
  - name: hierarchyDepthLimit
    type: number
    required: false
    description: Maximum recursion depth when traversing role hierarchies for derived permissions.
    default: 5
    validation:
      minimum: 1
      maximum: 10

schema:
  role_catalog:
    type: AuthzRoleDocument[]
    required: true
    description: Canonical RBAC roles (R21.2 Part 4.2 TABLE 1).
    examples:
      [
        [
          {
            "id": "11111111-1111-4111-8111-111111111111",
            "name": "Owner",
            "description": "Full tenant access + invoice approval (R21.2 Table 1).",
          },
          {
            "id": "22222222-2222-4222-8222-222222222222",
            "name": "Approver",
            "description": "Workflow approver for compliance-sensitive documents.",
          },
          {
            "id": "33333333-3333-4333-8333-333333333333",
            "name": "Editor",
            "description": "Contributor allowed to create + update documents in scope.",
          },
        ],
      ]
    default: []
  permission_catalog:
    type: AuthzPermissionDocument[]
    required: true
    description: Atomic permissions following resource:action notation (TABLE 2).
    default: []
  role_permissions:
    type: Record<string, string[]>
    required: true
    description: Junction map for role→permission edges (TABLE 3).
    default: {}
  membership_records:
    type: AuthzMembershipDocument[]
    required: true
    description: SaaS membership triple (user_id, organization_id, role_id) with UNIQUE constraint (TABLE 4).
    default: []
  role_hierarchy_edges:
    type: AuthzRoleHierarchyEdge[]
    required: false
    description: Parent→child adjacency list for hierarchical RBAC (Part 3.1).
    default: []
  session_roles:
    type: string[]
    required: false
    description: Materialized roles granted within the current session/token exchange.
    default: []

semantics:
  membership_records:
    semantic_type: authorization.memberships
    token_mapping: tokenMap(authorization.memberships)
    ui_hints:
      component: MembershipMatrix
      uniqueConstraint: user_id+organization_id+role_id
  role_catalog:
    semantic_type: authorization.roles
    token_mapping: tokenMap(authorization.roles)
    ui_hints:
      component: RoleCatalogPanel
  permission_catalog:
    semantic_type: authorization.permissions
    token_mapping: tokenMap(authorization.permissions)
    ui_hints:
      component: PermissionList

view_extensions:
  list:
    - component: RoleBadgeList
      position: after
      props:
        rolesField: session_roles
        fallbackRoleParameter: defaultRoleId
  detail:
    - component: MembershipPanel
      position: main
      priority: 75
      props:
        membershipsField: membership_records
        hierarchyField: role_hierarchy_edges
        roleField: role_catalog
        permissionField: permission_catalog
  form:
    - component: RoleAssignmentForm
      position: main
      props:
        availableRolesField: role_catalog
        membershipField: membership_records
        defaultRoleParameter: defaultRoleId

tokens:
  auth.roles.badge.bg: "var(--sys-surface-neutral)"
  auth.roles.badge.text: "var(--sys-text-strong)"
  auth.membership.card.border: "var(--sys-border-strong)"
  auth.membership.card.bg: "var(--sys-surface-raised)"

dependencies: []

metadata:
  created: "2025-11-19"
  owners:
    - security@oods.systems
    - platform@oods.systems
  maturity: experimental
  accessibility:
    keyboard: RoleAssignmentForm keeps add/remove buttons in reading order.
    screenreader: MembershipPanel announces organization, role, and permission counts per entry.
  regionsUsed:
    - list
    - detail
    - form
  examples:
    - User
    - Organization
  references:
    - "R21.2 Canonical Data Models for Authorization Systems"