Field-level and column-level security

Applications often need to control access not just at the resource level but at the field level. For example, an HR system might allow all employees to view a colleague’s name and department, but restrict salary information to HR staff and managers.

Pattern 1: Actions as field operations

Model each field-action combination as a distinct action using the hierarchical action naming convention (: delimiter).

Resource policy with field-level actions
apiVersion: api.cerbos.dev/v1
resourcePolicy:
  resource: "employee_record"
  version: "default"
  rules:
    - actions: ["name:view", "department:view", "title:view"]
      effect: EFFECT_ALLOW
      roles: ["employee"]

    - actions: ["salary:*"]
      effect: EFFECT_ALLOW
      roles: ["hr_admin"]

    - actions: ["salary:view"]
      effect: EFFECT_ALLOW
      derivedRoles:
        - direct_manager

Check multiple field-level actions in a single request:

Request
{
  "principal": {
    "id": "alice",
    "roles": ["employee"]
  },
  "resources": [
    {
      "resource": {
        "kind": "employee_record",
        "id": "emp-001"
      },
      "actions": ["name:view", "department:view", "salary:view"]
    }
  ]
}
Response
{
  "results": [
    {
      "resource": { "id": "emp-001", "kind": "employee_record" },
      "actions": {
        "name:view": "EFFECT_ALLOW",
        "department:view": "EFFECT_ALLOW",
        "salary:view": "EFFECT_DENY"
      }
    }
  ]
}

Alice can view name and department but not salary.

Wildcards respect the : delimiter. A rule with actions: ["salary:*"] matches both salary:view and salary:edit.

Pattern 2: Output expressions for permitted fields

Use output expressions to return the set of fields a user can access, so your application can dynamically build responses.

Resource policy with output expressions
apiVersion: api.cerbos.dev/v1
resourcePolicy:
  resource: "employee_record"
  version: "default"
  rules:
    - name: base-fields
      actions: ["view"]
      effect: EFFECT_ALLOW
      roles: ["employee"]
      output:
        when:
          ruleActivated: |-
            {"viewable_fields": ["name", "department", "title"]}

    - name: sensitive-fields
      actions: ["view"]
      effect: EFFECT_ALLOW
      roles: ["hr_admin"]
      output:
        when:
          ruleActivated: |-
            {"viewable_fields": ["name", "department", "title", "salary", "ssn"]}

The response outputs array contains the field lists from all matched rules. Your application merges these to determine the full set of accessible fields.

Response outputs
{
  "outputs": [
    {
      "src": "resource.employee_record.vdefault#base-fields",
      "val": {
        "viewable_fields": ["name", "department", "title"]
      }
    }
  ]
}

Choosing a pattern

Actions as field operations

Best when you need yes/no decisions per field and want to leverage Cerbos wildcard matching. Works well with PlanResources for query-level filtering.

Output expressions

Best when you want to return a dynamic set of permitted fields from a single action check. More flexible but requires application-side logic to process the output.

These patterns can be combined — for example, use action-based checks for write operations and output expressions for read operations.