AccessVoter

Represents an independent access control voter that evaluates authorization requests and votes allow, deny, or abstain based on specific criteria. Inspired by Symfony's Voter pattern and Spring Security's AccessDecisionVoter, this entity enables modular, composable authorization logic where different voters check different aspects of an access request (permissions, ownership, business rules, time restrictions, IP location, etc.). Each voter is responsible for one authorization concern and votes based on its evaluation. Multiple voters can be combined using an AccessDecisionStrategy to reach a final decision. Voters support different evaluation types including permission-based (checking user permissions), ownership-based (checking if user owns the resource), attribute-based (evaluating user/resource attributes), rule-based (custom business logic), and time-based (checking access windows). The entity enables separation of authorization concerns, testable access control logic, and flexible security policies across enterprise applications and multi-tenant platforms.

10 properties
Schema

Properties

PropertyTypeModeDescriptionRequired
namestring
stored

Unique identifier for the voter

Example: "permission-voter"

Required
labelstring
stored

Human-readable display name for the voter

Example: "Permission-Based Voter"

Required
descriptionstring
stored

Detailed explanation of what this voter checks and when it votes

Example: "Checks if user has the required permission via UserPermission grants. Votes ALLOW if permission found, ABSTAIN otherwise."

Optional
voterTypestring
stored

Type of authorization check this voter performs

Values: permission-based, ownership-based, attribute-based, rule-based, time-based, location-based, tenant-based, custom

Example: "permission-based"

Required
prioritynumber
stored

Priority order for voter execution (lower number = higher priority, executed first)

Example: 100

Required
isEnabledboolean
stored

Whether this voter is currently active and participating in access decisions

Example: true

Required
supportedEntitiesstring[]
stored

Entity types this voter can evaluate (empty means all entities)

Example: ["users","invoices","reports"]

Optional
supportedActionsPermissionAction[]
stored

Actions this voter can evaluate (empty means all actions)

Optional
configurationjson
stored

Voter-specific configuration (evaluation rules, attribute mappings, business logic parameters)

Example: {"checkTenantMembership":true,"requireActiveStatus":true}

Optional
metadatajson
stored

Additional voter metadata

Optional

Examples

Example 1

{
  "@type": "AccessVoter",
  "name": "permission-voter",
  "label": "Permission-Based Voter",
  "description": "Checks if user has required permission via UserPermission. Votes ALLOW if permission found and active, ABSTAIN otherwise.",
  "voterType": "permission-based",
  "priority": 100,
  "isEnabled": true,
  "configuration": {
    "checkExpiration": true,
    "checkTenantScope": true
  }
}

Example 2

{
  "@type": "AccessVoter",
  "name": "ownership-voter",
  "label": "Resource Ownership Voter",
  "description": "Checks if user owns or created the resource. Votes ALLOW if user is owner, ABSTAIN otherwise.",
  "voterType": "ownership-based",
  "priority": 200,
  "isEnabled": true,
  "supportedEntities": [
    "reports",
    "documents",
    "projects"
  ],
  "configuration": {
    "ownershipField": "createdBy"
  }
}

Example 3

{
  "@type": "AccessVoter",
  "name": "business-hours-voter",
  "label": "Business Hours Voter",
  "description": "Checks if access is during allowed business hours. Votes DENY if outside hours, ABSTAIN if during hours.",
  "voterType": "time-based",
  "priority": 50,
  "isEnabled": true,
  "configuration": {
    "allowedHours": "09:00-17:00",
    "allowedDays": [
      "monday",
      "tuesday",
      "wednesday",
      "thursday",
      "friday"
    ],
    "timezone": "America/New_York"
  }
}

Example 4

{
  "@type": "AccessVoter",
  "name": "ip-whitelist-voter",
  "label": "IP Whitelist Voter",
  "description": "Checks if request comes from whitelisted IP. Votes DENY if not whitelisted, ABSTAIN if whitelisted.",
  "voterType": "location-based",
  "priority": 10,
  "isEnabled": true,
  "configuration": {
    "requireWhitelist": true,
    "checkTenantWhitelist": true
  }
}

Example 5

{
  "@type": "AccessVoter",
  "name": "tenant-membership-voter",
  "label": "Tenant Membership Voter",
  "description": "Checks if user is active member of the tenant. Votes DENY if not member or inactive, ABSTAIN if active member.",
  "voterType": "tenant-based",
  "priority": 20,
  "isEnabled": true,
  "configuration": {
    "requireActiveStatus": true,
    "checkTenantSubscription": true
  }
}

Example 6

{
  "@type": "AccessVoter",
  "name": "custom-approval-voter",
  "label": "Approval Workflow Voter",
  "description": "Checks custom business rules for approval workflows. Votes based on approval state, hierarchy, and delegation rules.",
  "voterType": "custom",
  "priority": 300,
  "isEnabled": true,
  "supportedEntities": [
    "invoices",
    "purchase-orders"
  ],
  "supportedActions": [
    {
      "@type": "PermissionAction",
      "name": "approve"
    }
  ],
  "configuration": {
    "requireManagerApproval": true,
    "amountThreshold": 10000,
    "allowDelegation": true
  }
}