What is AuthZEN?
AuthZEN (AuthZ ENhancement) is an OpenID Foundation initiative that standardizes fine-grained authorization, similar to how OpenID Connect standardized authentication.
AuthZEN creates interoperability between:
- Policy Enforcement Points (PEPs): Applications that need authorization decisions.
- Policy Decision Points (PDPs): Services that evaluate policies and return decisions.
IndyKite is an AuthZEN-compliant PDP that uses its Identity Knowledge Graph (IKG) to make intelligent, context-aware authorization decisions.
Why use AuthZEN?
What problem does AuthZEN solve for interoperability?
Problem: The authorization landscape is fragmented. Different vendors use proprietary APIs, protocols, and policy languages, creating vendor lock-in and integration challenges.
AuthZEN's Solution: A standardized communication protocol between PEPs and PDPs. Any application can query any AuthZEN-compliant PDP, regardless of the underlying policy engine.
IndyKite Benefit: Organizations can use IndyKite's advanced KBAC capabilities alongside other AuthZEN-compliant components without vendor lock-in.
How does AuthZEN simplify development?
Problem: Developers often "reinvent the authorization wheel" for each application, leading to inconsistent implementations and security vulnerabilities.
AuthZEN's Solution: Standardized JSON-based request/response formats with core entities:
subject: Who is requesting accessaction: What operation they want to performresource: What they want to accesscontext: Additional environmental data
IndyKite Benefit: Developers use the standard AuthZEN interface instead of learning a proprietary API, reducing integration time.
Why externalize authorization?
Problem: Embedding authorization logic in applications makes it difficult to manage, update, and audit. Fine-grained access control (e.g., "Can Alice view this specific document at this time?") becomes unscalable.
AuthZEN's Solution: Externalize authorization to dedicated PDPs that make dynamic, real-time decisions based on subject, resource, action, and context.
IndyKite Benefit: IndyKite's Identity Knowledge Graph enables complex, relationship-based authorization. Access decisions are based on "who you are, what you're trying to do, with what, from where, and why" — not just static roles.
How does AuthZEN improve security and compliance?
Problem: Inconsistent authorization creates security gaps and makes compliance difficult to demonstrate.
AuthZEN's Solution: Continuous authorization enforcement, dynamic separation of duties, and clear audit trails.
IndyKite Benefit: The IKG continuously updates with real-time data, enabling dynamic and adaptive access decisions that support "least privilege" and "zero trust" policies.
How do I make an AuthZEN request?
Single Evaluation Request
Endpoint:
- EU:
POST https://eu.api.indykite.com/access/v1/evaluation - US:
POST https://us.api.indykite.com/access/v1/evaluation
Request Syntax
{
"subject": {
"type": "<string>",
"id": "<string>"
},
"resource": {
"type": "<string>",
"id": "<string>"
},
"action": {
"name": "<string>"
},
"context": {
"input_params": {
"<key>": "<value>"
}
}
}
What does each field mean?
| Field | Description | Example |
subject.type |
The type of entity requesting access (maps to node label in IKG) | "User", "Service" |
subject.id |
Unique identifier for the subject (maps to external_id in IKG) | "alice@example.com" |
resource.type |
The type of resource being accessed (maps to node label in IKG) | "Document", "API" |
resource.id |
Unique identifier for the resource (maps to external_id in IKG) | "project_alpha_specs.pdf" |
action.name |
The operation being requested | "CAN_READ", "CAN_EDIT" |
context.input_params |
Additional contextual data for policy evaluation. Also carries location parameters for 3.0-kbac policies on a composite IKG (see below) |
{"ip_address": "192.168.1.100"}, {"region": "east"} |
Request Example
{
"subject": {
"type": "User",
"id": "alice@example.com"
},
"resource": {
"type": "Document",
"id": "project_alpha_specs.pdf"
},
"action": {
"name": "CAN_READ"
},
"context": {
"input_params": {
"ip_address": "192.168.1.100",
"time_of_day": "14:30:00Z",
"device_type": "laptop"
}
}
}
Response Syntax
{
"decision": <boolean>,
"context": {
"advice": [{
"error": "<string>",
"error_description": "<string>"
}]
}
}
What does the response contain?
| Field | Description |
decision |
true = access allowed, false = access denied |
context.advice |
Optional array of advice objects explaining why access was denied |
advice.error |
Error code (e.g., "insufficient_user_authentication") |
advice.error_description |
Human-readable explanation of the denial |
Response Example (Denied)
{
"decision": false,
"context": {
"advice": [{
"error": "insufficient_user_authentication",
"error_description": "Authentication is expired"
}]
}
}
How does IndyKite process an AuthZEN request?
When IndyKite receives an AuthZEN request, it:
- Maps request to graph entities: The
subject,resource,action, andcontextare mapped to nodes and relationships in the Identity Knowledge Graph.
- Evaluates KBAC policies: Policies defined as graph traversals are evaluated against real-time data.
Example policy logic:
- "Allow
UsertoCAN_READDocumentIFUserIS_MEMBER_OFTeamANDDocumentIS_ASSIGNED_TOProjectANDTeamIS_ASSIGNED_TOProject" - "Deny access IF
context.ip_addressis NOT intrusted_network"
- "Allow
- Returns decision: An AuthZEN-compliant response with
decision(true/false) and optionaladviceexplaining the decision.
How do I batch multiple evaluations?
Use the batch endpoint to evaluate multiple authorization requests in a single call.
Endpoint:
- EU:
POST https://eu.api.indykite.com/access/v1/evaluations - US:
POST https://us.api.indykite.com/access/v1/evaluations
Batch Request Syntax
{
"subject": {
"type": "<string>",
"id": "<string>"
},
"resource": {
"type": "<string>",
"id": "<string>"
},
"action": {
"name": "<string>"
},
"context": {
"input_params": {},
"policy_tags": ["<string>"]
},
"evaluations": [{
"subject": {
"type": "<string>",
"id": "<string>"
},
"resource": {
"type": "<string>",
"id": "<string>"
},
"action": {
"name": "<string>"
},
"context": {
"input_params": {},
"policy_tags": ["<string>"]
}
}]
}
How do default values work in batch requests?
Fields defined at the top level serve as defaults for all evaluations. Each evaluation can override these defaults.
| Field | Required | Description |
subject |
Optional | Default subject for all evaluations. Useful when the same user accesses multiple resources. |
resource |
Optional | Default resource for all evaluations. Overridden by evaluation-specific resource. |
action |
Optional | Default action for all evaluations. Overridden by evaluation-specific action. |
context |
Optional | Default context for all evaluations. Overridden by evaluation-specific context. |
evaluations |
Required | Array of individual evaluation objects to process. |
What are policy_tags?
The policy_tags field allows you to filter which policies are evaluated for a request. Only policies with matching tags will be considered.
Batch Request Example
{
"subject": {
"type": "User",
"id": "alice@example.com"
},
"action": {
"name": "CAN_READ"
},
"evaluations": [
{
"resource": {
"type": "Document",
"id": "doc_001"
}
},
{
"resource": {
"type": "Document",
"id": "doc_002"
}
},
{
"resource": {
"type": "Folder",
"id": "folder_001"
},
"action": {
"name": "CAN_LIST"
}
}
]
}
This example evaluates:
- Can Alice READ doc_001?
- Can Alice READ doc_002?
- Can Alice LIST folder_001? (overrides default action)
Which KBAC policy versions answer AuthZEN requests?
The decisions behind every AuthZEN endpoint come from KBAC policies. Two policy versions exist, selected by meta.policy_version in the policy JSON:
| Aspect | 2.0-kbac |
3.0-kbac |
| Condition Cypher handling | Rewritten by the platform into evaluation and search variants | Raw: runs as authored; the platform only pins subject/resource and appends the projection |
| Composite-database routing (data residency) | None: always the default database | USE graph.byName(...) clauses, static or via location parameters supplied in context.input_params |
| Allowed Cypher clauses | No CALL, no RETURN |
CALL { } subqueries and inner RETURNs allowed; mutating clauses still blocked |
| Policy JSON schema | Identical: only meta.policy_version differs |
|
A valid 2.0-kbac condition is also a valid 3.0-kbac condition: you can carry a policy over just by changing meta.policy_version, with two caveats: $subject_id must not be referenced (see below), and the platform-bound parameters ($subject_external_id, $subject_type, $resource_external_id, $resource_type) are bound automatically and never supplied via input_params.
$subject_id is not available in 3.0-kbac
A 3.0-kbac condition must not reference $subject_id: on a composite IKG the subject's internal node ID is not stable across locations, so 3.0-kbac identifies subjects by type and external ID only. Creating a policy that references it fails with 422 Unprocessable Entity:
{
"message": "Unprocessable Entity",
"errors": [
"invalid policy config: parameter \"$subject_id\" is reserved and cannot be referenced"
]
}
No replacement is needed: the platform already pins the subject by type and external ID in every 3.0-kbac query.
How do I request a decision in a specific location?
On a composite IKG (see the data residency guide), a 3.0-kbac policy can route with a dynamic parameter, for example USE graph.byName($region). The AuthZEN request then supplies the logical location (a key of the project's alias_mapping) through context.input_params: no new endpoint or field is involved:
{
"subject": {
"type": "Person",
"id": "person-alice"
},
"resource": {
"type": "Car",
"id": "car-kitt"
},
"action": {
"name": "CAN_DRIVE"
},
"context": {
"input_params": {
"region": "east"
}
}
}
This works identically on /access/v1/evaluation, /access/v1/evaluations (put the location in the default or per-evaluation context), and the three search endpoints.
Failure modes:
- Omitting a required location parameter, passing a non-string, or naming a location that is not in
alias_mappingfails the call with422 Unprocessable Entity. - Using a location parameter against a project without a composite database fails with
422 Unprocessable Entity. - Bearer-token calls where the token's subject differs from the requested
subjectare denied with403 Forbidden.
What credentials do I need?
- AppAgent credentials: Required for all AuthZEN requests.
- User access token: Required if subject is a user (not _Application).
Authentication header: X-IK-ClientKey: <AppAgent-token>
Next Steps
- KBAC concepts: Dynamic Authorization Guide
- Data residency and 3.0-kbac routing: Data Residency Guide
- Full examples: Developer Hub Resources
- Credentials guide: Credentials Guide
- OpenID AuthZEN specification: https://openid.net/wg/authzen/
