Access is not authority
A PDP permit says the subject may act in general. Decionis still decides whether this exact action, with this amount, target, risk, prior sequence and any required human approval, executes now.
Most institutions already have a policy decision point that answers the OpenID AuthZEN question: may this subject perform this action on this resource? Decionis does not replace it or re-ask it. Its answer travels into the authority request as a material signal, and Decionis answers the different question it owns: does this exact execution have authority now, under your policy, with proof afterwards.
AuthZEN is an input to authority, never the protocol core. The PDP is consulted in your process before the authority request; nothing calls out from inside evaluation.
Okta / Entra / SGNL / any AuthZEN PDP
│ access decision (POST /access/v1/evaluation → { decision })
▼
Decionis ← the answer arrives as signals.upstream_authorization
│ deterministic execution authority over policy + request + supplied facts
▼
ExecutionBinding → pre-commit claim → execution → signed dossierA PDP permit says the subject may act in general. Decionis still decides whether this exact action, with this amount, target, risk, prior sequence and any required human approval, executes now.
Decionis never overrides an upstream refusal. The starter policy turns a PDP deny into BLOCK before any other rule runs.
A missing, unreachable, unlisted or tampered PDP answer never becomes a permit. required_signals and signal_admission resolve it to ESCALATE (or BLOCK, if you say so).
createAuthZenEntitlementProvider calls the PDP over HTTPS at an allow-listed origin, parses the AuthZEN 1.0 response strictly, digests the exact request and response, and packs the answer into an upstream_authorization signal.
import { DecionisNodeSdk, createAuthZenEntitlementProvider } from "@decionis/sdk";
const pdp = createAuthZenEntitlementProvider({
pdpUrl: "https://pdp.example.com", // your AuthZEN policy decision point
headers: { authorization: `Bearer ${process.env.PDP_TOKEN}` },
});
// 1. Ask the PDP the AuthZEN question, in your process, before Decionis.
const { context, result } = await pdp.enrichContext(
{
subject: { type: "agent", id: "agent:treasury-bot" },
resource: { type: "account", id: "acct:ops-eur" },
action: { name: "payment.release" },
},
{ channel: "api" },
);
// result.ok === false → no signal was attached; the policy's fail-safe applies.
// 2. Ask Decionis the execution-authority question, with the answer as a fact.
const decision = await sdk.evaluateDecision({
decision_type: "payment.release",
amount: 25_000,
context,
});| Field | Meaning |
|---|---|
| kind | upstream_authorization — a built-in semantic signal kind |
| producer.provider | The PDP's identity (its origin by default); must appear in the policy's allowed_producers |
| producer.detector_version | authzen/1.0 |
| value.decision | The PDP's boolean answer |
| value.subject / resource / action | Exactly what was asked, without properties |
| value.request_digest / response_digest | RFC 8785 digests of the request and response bodies |
| evidence_digest | The response digest, so require_evidence_digest sees the PDP's own bytes |
| value_digest | Recomputed by the Protocol; a mismatch refuses the signal |
| material | true — the answer enters the execution binding and is revalidated at claim |
provider.discover() reads /.well-known/authzen-configuration and adopts the evaluation endpoint it names only when that endpoint's origin is allow-listed. A document that points elsewhere is ignored.
The answer is read like any other fact. buildAuthZenStarterPolicyBundle in @decionis/shared ships this shape, tested verbatim through the ingestion schema and the evaluator.
{
"required_signals": ["upstream_authorization"],
"metadata": {
"signal_admission": {
"allowed_producers": ["https://pdp.example.com"],
"allowed_detector_versions": ["authzen/1.0"],
"require_evidence_digest": true,
"minimum_confidence_basis_points": 10000,
"on_failure": "ESCALATE"
}
},
"rules": [
{
"rule_id": "authzen_block_upstream_deny",
"when": { "all": [{ "field": "signals.upstream_authorization.decision", "operator": "EQ", "value": false }] },
"then": { "action": "AUTO_REJECT", "severity": "urgent" },
"priority": 300
},
{
"rule_id": "authzen_escalate_permitted_over_desk_limit",
"when": { "all": [
{ "field": "signals.upstream_authorization.decision", "operator": "EQ", "value": true },
{ "field": "amount", "operator": "GT", "value": 1000 }
] },
"then": { "action": "ESCALATE", "severity": "elevated", "sla_minutes": 60 },
"priority": 200
}
]
}| Situation | Resolution |
|---|---|
| PDP said deny | BLOCK (authzen_block_upstream_deny) |
| PDP said permit, amount within the desk limit | ALLOW |
| PDP said permit, amount above the desk limit | ESCALATE — a named person decides |
| No PDP answer in the request | ESCALATE via required_signals (missing_required_signals) |
| Answer from a PDP not in allowed_producers | ESCALATE via signal_admission (producer_not_allowed) |
| Answer altered after the PDP returned it | ESCALATE — value_digest_mismatch; the signal is dropped |
Nothing new is added to the Decision Dossier for this. The envelope is recorded verbatim inside the signed inputs snapshot, so a verifier already sees which PDP said what, when, over which request.
inputs_snapshot.context.signals.upstream_authorization carries the full envelope; signal_provenance records producer, version, digests and whether it was admitted. The verdict replays offline from the dossier with no call to the PDP.
Because the signal is material, its id, version, observation time and digests are part of the execution binding. A different PDP answer at claim time is a stale-state rejection, not a silent re-permit.
Some gateways now ask a policy decision point over AuthZEN and enforce the answer before a request is forwarded. Traefik Hub's AuthZEN middleware (early access from v3.21.0-ea.3; Sovereign Trust Plane, September 2026) is one, with OpenFGA, Keycloak, OPA and Cerbos named as decision points. Decionis composes underneath such a gateway; it does not replace it.
The gateway's record says which subject was allowed to reach which tool, under which policy, and that the record was not altered afterwards. The Decision Dossier says whether this exact action had authority at the moment it committed, and what its observed effect was. Keep both. Neither replaces the other, and the dossier does not describe the gateway's log.
The provider asks the PDP in your code so the exact request and answer are digested and travel inside the signed inputs snapshot. Whether a gateway forwards its own AuthZEN decision to the upstream service is that gateway's documentation to check; Traefik Hub's AuthZEN guide, read on 22 September 2026, does not describe forwarding the decision, so the provider's own call is the path this page documents.
Recorded on 22 September 2026 against Cerbos PDP 0.55.0 over AuthZEN 1.0: the provider adopted the discovery document's evaluation endpoint, a permit and a deny came back as material signals, and the Protocol replays the exact exchange through the starter bundle — the permit is allowed within the desk limit and escalated above it, the deny is blocked. The recording is committed in the SDK's test fixtures; Cerbos is named as the decision point used, not as a partner.
What this integration is, and is not.
Decionis does not expose an AuthZEN evaluation endpoint. A boolean decision cannot carry ESCALATE, which is the outcome this product exists to produce.
The Protocol never fetches during evaluation. The PDP is consulted by your code, in your process, and the evaluator stays a deterministic function of policy, request and supplied facts.
Decionis is not a member of the OpenID Foundation. AuthZEN is referenced as the published Authorization API 1.0 (January 2026); Okta, Microsoft Entra and SGNL are named as examples of policy decision points, not as partners.