KBAC: Check a Permission Grid for One Subject with authZEN Evaluations (Boxcar)
This example demonstrates the authZEN /access/v1/evaluations (boxcarring) endpoint to discover what one subject can do across several (resource, action) cells in a single round-trip.
Note: the older /access/v1/what-authorized endpoint is deprecated. Use /access/v1/evaluations (this example) for grid checks, or the search endpoints for type-level discovery.
How the evaluations endpoint works:
- Top-level subject / action / resource act as defaults.
- Each entry in the evaluations array can override any of them; missing fields inherit the defaults.
- The response is an evaluations array with one { decision: true|false } per request, in the same order.
How it relates to the search endpoints:
- /search/action - "for THIS subject + THIS resource, which actions are allowed?"
- /search/resource - "for THIS subject + THIS action, which resources are allowed?"
- /search/subject - "for THIS resource + THIS action, which subjects are allowed?"
- /evaluations - "for THIS subject, decide each of these concrete (resource, action) cells at once."
Use /evaluations when you already know the concrete resources to check. For type-level discovery ("which cars can the subject drive?") use /search/resource (see authz-1 and authz-4).
Use case
Scenario: A self-service portal renders a side menu. Each item maps to a concrete (resource, action) cell. Before rendering, the portal asks IndyKite which items are available to the signed-in user in one boxcar call.
Default subject: Karel
Candidate cells:
- (Car kitt, CAN_DRIVE)
- (Bus harmonika, CAN_RIDE)
- (Car kitt, CAN_WASH)
Policies in scope:
- Person can CAN_DRIVE a Car if a DRIVES relationship exists.
- Person can CAN_RIDE a Bus if they hold a Ticket for it (Person -HAS-> Ticket -FOR-> Bus).
- (No CAN_WASH policy defined.)
Karel holds a Ticket (listek) that is FOR the Harmonika bus, but does not drive kitt and no CAN_WASH policy applies. The evaluations response is therefore [false, true, false] - one decision per cell, in order.
Render only the menu item whose decision is true (CAN_RIDE the bus); leave the others hidden or grayed out.

Requirements
Prerequisites:
- ServiceAccount credentials: For creating the policies.
- AppAgent credentials: For calling /access/v1/evaluations (X-IK-ClientKey).
- Graph data including Person, Car, Bus, and Ticket nodes, with DRIVES relationships and a Person -HAS-> Ticket -FOR-> Bus path.
- At least one policy per (resource, action) cell you want to evaluate.
Required API access:
- POST /configs/v1/authorization-policies (one per action)
- POST /access/v1/evaluations
Steps
Step 1: Capture Graph Data
- Action: POST Person, Car, Bus, Ticket nodes; DRIVES relationships and the Person -HAS-> Ticket -FOR-> Bus path.
- Result: Karel -HAS-> Ticket(listek) -FOR-> Bus(harmonika); no DRIVES from Karel.
Step 2: Create Per-Action Policies
- Action: POST one policy for CAN_DRIVE on Car, one for CAN_RIDE on Bus. Leave CAN_WASH undefined intentionally.
- Result: Policy IDs returned.
Step 3: Call /access/v1/evaluations
- Authentication: AppAgent credential.
- Action: POST a default subject (Karel) plus an evaluations array of concrete (resource, action) cells.
- Result: An evaluations array with one decision per cell, in order. Keep the cells where decision is true.
Step 1
Capture nodes used in this example. Re-use the authZEN dataset.
{
"nodes": [
{
"external_id": "alice",
"is_identity": true,
"type": "Person",
"properties": [
{
"type": "email",
"value": "alice@email.com"
},
{
"type": "given_name",
"value": "Alice"
},
{
"type": "last_name",
"value": "Smith"
}
]
},
{
"external_id": "knightrider",
"type": "Person",
"is_identity": true,
"properties": [
{
"type": "email",
"value": "knightrider@demo.com"
},
{
"type": "name",
"value": "Michael Knight"
}
]
},
{
"external_id": "satchmo",
"type": "Person",
"is_identity": true,
"properties": [
{
"type": "email",
"value": "satchmo@demo.com"
},
{
"type": "name",
"value": "Louis Armstrong"
}
]
},
{
"external_id": "karel",
"type": "Person",
"is_identity": true,
"properties": [
{
"type": "email",
"value": "karel@demo.com"
},
{
"type": "name",
"value": "Karel Plihal"
}
]
},
{
"external_id": "kitt",
"type": "Car",
"is_identity": false,
"properties": [
{
"type": "manufacturer",
"value": "pontiac"
},
{
"type": "model",
"value": "Firebird"
}
]
},
{
"external_id": "cadillacv16",
"type": "Car",
"is_identity": false,
"properties": [
{
"type": "manufacturer",
"value": "Cadillac"
},
{
"type": "model",
"value": "V-16"
}
]
},
{
"external_id": "harmonika",
"type": "Bus",
"is_identity": false,
"properties": [
{
"type": "manufacturer",
"value": "Ikarus"
},
{
"type": "model",
"value": "280"
}
]
},
{
"external_id": "listek",
"type": "Ticket",
"is_identity": false
},
{
"external_id": "airbook-xyz",
"type": "Laptop",
"is_identity": false
}
]
}Capture DRIVES relationships plus the Person -HAS-> Ticket -FOR-> Bus path (karel HAS listek, listek FOR harmonika).
{
"relationships": [
{
"source": {
"external_id": "knightrider",
"type": "Person"
},
"target": {
"external_id": "kitt",
"type": "Car"
},
"type": "DRIVES"
},
{
"source": {
"external_id": "satchmo",
"type": "Person"
},
"target": {
"external_id": "cadillacv16",
"type": "Car"
},
"type": "DRIVES"
},
{
"source": {
"external_id": "karel",
"type": "Person"
},
"target": {
"external_id": "listek",
"type": "Ticket"
},
"type": "HAS"
},
{
"source": {
"external_id": "listek",
"type": "Ticket"
},
"target": {
"external_id": "harmonika",
"type": "Bus"
},
"type": "FOR"
},
{
"source": {
"external_id": "karel",
"type": "Person"
},
"target": {
"external_id": "airbook-xyz",
"type": "Laptop"
},
"type": "OWNS"
},
{
"source": {
"external_id": "alice",
"type": "Person"
},
"target": {
"external_id": "airbook-xyz",
"type": "Laptop"
},
"type": "OWNS"
},
{
"source": {
"external_id": "knightrider",
"type": "Person"
},
"target": {
"external_id": "kitt",
"type": "Car"
},
"type": "OWNS"
},
{
"source": {
"external_id": "alice",
"type": "Person"
},
"target": {
"external_id": "cadillacv16",
"type": "Car"
},
"type": "DRIVES"
}
]
}Step 2
CAN_DRIVE policy (Person -[DRIVES]-> Car).
{
"meta": {
"policy_version": "2.0-kbac"
},
"subject": {
"type": "Person"
},
"actions": [
"CAN_DRIVE"
],
"resource": {
"type": "Car"
},
"condition": {
"cypher": "MATCH (subject:Person)-[:DRIVES]->(resource:Car)"
}
}Request to create the CAN_DRIVE policy.
{
"project_id": "your_project_gid",
"description": "description of policy",
"display_name": "policy name",
"name": "policy-name",
"policy": "{\"meta\":{\"policy_version\":\"2.0-kbac\"},\"subject\":{\"type\":\"Person\"},\"actions\":[\"CAN_DRIVE\"],\"resource\":{\"type\":\"Car\"},\"condition\":{\"cypher\":\"MATCH (subject:Person)-[:DRIVES]->(resource:Car)\"}}",
"status": "ACTIVE",
"tags": []
}CAN_RIDE policy (Person -HAS-> Ticket -FOR-> Bus).
{
"meta": {
"policy_version": "2.0-kbac"
},
"subject": {
"type": "Person"
},
"actions": [
"CAN_RIDE"
],
"resource": {
"type": "Bus"
},
"condition": {
"cypher": "MATCH (subject:Person)-[:HAS]->(ticket:Ticket)-[:FOR]->(resource:Bus)"
}
}Request to create the CAN_RIDE policy.
{
"project_id": "your_project_gid",
"description": "Authorize CAN_RIDE on Bus when the subject holds a Ticket for it (Person -HAS-> Ticket -FOR-> Bus).",
"display_name": "policy - person can ride a bus",
"name": "policy-person-can-ride-a-bus",
"policy": "{\"meta\":{\"policy_version\":\"2.0-kbac\"},\"subject\":{\"type\":\"Person\"},\"actions\":[\"CAN_RIDE\"],\"resource\":{\"type\":\"Bus\"},\"condition\":{\"cypher\":\"MATCH (subject:Person)-[:HAS]->(ticket:Ticket)-[:FOR]->(resource:Bus)\"}}",
"status": "ACTIVE",
"tags": []
}Step 3
Boxcar evaluations: a default subject (Karel) plus three concrete (resource, action) cells to decide at once.
{
"subject": {
"type": "Person",
"id": "karel"
},
"evaluations": [
{
"resource": {
"type": "Car",
"id": "kitt"
},
"action": {
"name": "CAN_DRIVE"
}
},
{
"resource": {
"type": "Bus",
"id": "harmonika"
},
"action": {
"name": "CAN_RIDE"
}
},
{
"resource": {
"type": "Car",
"id": "kitt"
},
"action": {
"name": "CAN_WASH"
}
}
]
}Response - one decision per cell, in request order: [CAN_DRIVE kitt = false, CAN_RIDE harmonika = true, CAN_WASH kitt = false].
{
"evaluations": [
{
"decision": false
},
{
"decision": true
},
{
"decision": false
}
]
}Same call in Python.
import http.client
import json
conn = http.client.HTTPSConnection("eu.api.indykite.com")
payload = json.dumps({
"subject": {"type": "Person", "id": "karel"},
"evaluations": [
{"resource": {"type": "Car", "id": "kitt"}, "action": {"name": "CAN_DRIVE"}},
{"resource": {"type": "Bus", "id": "harmonika"}, "action": {"name": "CAN_RIDE"}},
{"resource": {"type": "Car", "id": "kitt"}, "action": {"name": "CAN_WASH"}}
]
})
headers = {
'Content-Type': "application/json",
'X-IK-ClientKey': ""
}
conn.request("POST", "/access/v1/evaluations", payload, headers)
res = conn.getresponse()
data = res.read()