PermDock
Decisions

0011: AuthZEN 1.0 as the decision wire format

Why the decision endpoint and the pdp provider speak OpenID AuthZEN instead of a bespoke JSON format, and why certification is a target.

Status

Accepted, September 2026.

Context

PermDock needs a decision wire format in two directions. Outbound, the React client asks the server about closure grants that a snapshot cannot answer (the endpoint on PermDockProvider), and simulate() batches pre-flight checks for agent plans. Inbound, the pdp provider lets PermDock defer to an external policy decision point (Cerbos, Topaz, Keycloak, OPA behind a shim).

Kilpi's endpoint plugin is the closest prior art and it is bespoke: an unvalidated object: z.any(), a public-secret header, no batching contract, no discovery. Every hosted PDP has its own request shape.

The OpenID AuthZEN Authorization API 1.0 went final in January 2026. It defines POST /access/v1/evaluation (subject, action, resource, context in; decision and context out), /access/v1/evaluations for batched "boxcar" requests, /access/v1/search/subject, /search/resource and /search/action, .well-known/authzen-configuration PDP metadata, and a certification programme with Basic, Batch, Search and Discovery levels. Keycloak and the NLgov profile implement it.

The mapping to PermDock is almost one-to-one: evaluation is decide, evaluations is simulate, action search is "what can this subject do on this resource" (the catalog question), resource search is filter / where, subject search is the audit and admin question.

Decision

  • The client decision endpoint (permdockHandler() in permdock/next, the kernel handler in HTTP adapters) and the standalone permdock/authzen handler use AuthZEN 1.0 request and response schemas. PermDock-specific data (outcome, denials, alternatives, token, approval-required) travels in the AuthZEN context object, which the spec reserves for implementation-defined content.
  • permdock/authzen serves the full endpoint set plus .well-known/authzen-configuration.
  • The pdp provider is an AuthZEN PEP client, so PermDock can consume any certified PDP.
  • PermDock targets AuthZEN certification at the Basic, Batch, Search and Discovery levels once permdock/authzen ships in Phase 2.
  • The resource object in inbound requests is untrusted and validated at the boundary (0009). The endpoint requires real authentication; a shared "public secret" is not accepted.

Consequences

  • No bespoke wire format to document, version or defend; the AuthZEN spec and its test suite do that.
  • PermDock interoperates in both directions with Cerbos, Topaz, Keycloak and any other certified PDP without adapter code.
  • Batched client fetches (Kilpi's good idea) get a standard shape for free through evaluations.
  • Three outcomes must fit a spec whose decision is boolean: granted maps to true, denied and approval-required map to false with the PermDock outcome in context. Clients that only read decision remain fail-closed.
  • The AuthZEN subject is a single { type, id }; PermDock's actor and delegation ride in context and are documented in the wire formats page.
  • Certification is a marketing asset no TypeScript library has, and a maintenance commitment on every spec revision.

Alternatives considered

  • Bespoke JSON (Kilpi's endpoint, permix-style). Rejected: one more undocumented format, no interoperability, no external test suite.
  • GraphQL or tRPC for the decision endpoint. Rejected: framework-specific; AuthZEN is plain HTTP and works from React Native, MCP clients and PDPs.
  • OPA's data API or Cerbos's API as the "standard". Vendor formats; AuthZEN is the neutral one they are converging on.
  • Only the batched endpoint. Rejected; single evaluation is the Basic certification level and the simplest thing a client can call.

On this page