The XACML Model: PEP, PDP, PIP & PAP
The XACML reference architecture explained from first principles: the four-part pattern of policy enforcement point, policy decision point, policy information point, and policy administration point that almost every authorization system is built on. Learn each role through a plain analogy, follow a request through the whole decision flow, understand policy sets, rules, combining algorithms, and the four decision values, and see why XACML's XML faded while its architecture won everywhere.
A night at a members-only club
Sara wants to get into an exclusive members’ club. At the door, a doorkeeper stops her and radios the manager in the back office: “There’s a Sara here. Is she allowed in?” The manager checks the club’s rulebook, sees that it depends on her membership tier, and asks the records clerk to look her up. The clerk pulls her file: current member, gold tier, over eighteen. The manager reads the rule that gold members may enter at any time, says “let her in,” and the doorkeeper steps aside. The owner, who wrote that rulebook weeks ago, is nowhere near the door.
Four people, four jobs, and nobody does more than one. That separation is the architecture this article is about. The previous articles answered what an access decision should be based on: owners, labels, roles, attributes, policies, relationships. This one turns ninety degrees to a different question: however you decide, how do you build the machine that decides? What are its parts, who talks to whom, and where does policy live? The industry converged on one answer, the XACML reference architecture, and once you can see its four components in a system, every authorization product you meet stops being mysterious and becomes a variation on one familiar blueprint.
XACML stands for eXtensible Access Control Markup Language, an OASIS standard from the mid-2000s. Here’s what makes it worth a whole article: XACML’s language, its verbose XML syntax, is largely legacy today, replaced by friendlier successors. But its architecture, the way it splits an authorization system into four cooperating roles, won completely. Open Policy Agent, AWS Cedar, Amazon Verified Permissions, Zanzibar-style engines, your cloud’s IAM: look inside any of them and you’ll find the same four parts doing the same four jobs. We study XACML not to write its XML but because it gave us the vocabulary and the shape all modern authorization shares.
Four people, four jobs
The doorkeeper stops Sara at the entrance and, depending on the answer he gets, steps aside or blocks her. He doesn’t know the membership rules, doesn’t look anyone up, and doesn’t decide. He only asks and enforces. He’s the policy enforcement point (PEP).
The manager in the back office is the one who actually decides. The doorkeeper radios the question, and the manager, consulting the rules, answers “permit” or “deny.” She holds the logic, not the door. She’s the policy decision point (PDP).
The records clerk keeps the files. To decide, the manager often needs facts she doesn’t have: is Sara’s membership current, what tier is she, is she over eighteen? The clerk looks them up and reports back. He supplies information, nothing more. He’s the policy information point (PIP).
The owner wrote the house rules, “gold members enter any time, silver members before 10 p.m., nobody under eighteen,” and handed them to the manager before the club opened. She writes the rules ahead of time and is nowhere near the door when Sara arrives. She’s the policy administration point (PAP).
| Component | In the club | Its one job | What it doesn’t do |
|---|---|---|---|
| PEP, policy enforcement point | Doorkeeper | Intercept the request, ask for a decision, enforce it | Decide; store rules; look up attributes |
| PDP, policy decision point | Manager | Evaluate policy against the request, return a decision | Enforce; write rules; own the data |
| PIP, policy information point | Records clerk | Supply the attributes the PDP needs (user, resource, environment) | Decide; enforce |
| PAP, policy administration point | Owner | Write, manage, and publish policies, ahead of time | Take part in the live decision |
Two more pieces complete the picture. Between the PEP and the PDP there’s usually a context handler, the messenger that translates the application’s request into the PDP’s format, gathers the attributes the PDP asks for by calling the PIPs, and carries the decision back. Think of it as the manager’s assistant running between the office, the door, and the filing room so the manager can concentrate on deciding. XACML also names a policy retrieval point (PRP), the store the PDP loads policies from, the shelf where the owner’s rulebook sits. You won’t always see these two named, but they’re implied wherever the four main roles appear.
If you remember one sentence, make it this: the PEP asks and enforces, the PDP decides, the PIP informs, the PAP authors. The two pairs people mix up most each have a clean tell. The PEP touches the door, because enforcement lives with the application; the PDP touches the rules, because the decision lives in the engine. The PIP supplies facts about this request right now, such as whether Sara is a gold member; the PAP supplies rules written earlier, such as that gold members may enter. Facts now versus rules before is the whole difference.
A request in motion
Roles are clearest in motion. Here’s Sara’s request travelling through all four components and coming back as a decision, with the club labels alongside.
sequenceDiagram accTitle: How an access request flows through the XACML reference architecture accDescr: The diagram shows the ordered message flow for a single authorization request. First, the Policy Administration Point publishes policies to the decision engine ahead of time, marked as setup. Then Sara sends an access request to the Policy Enforcement Point. The enforcement point forwards the request to the context handler, which asks the Policy Decision Point for a decision. The decision point loads the applicable policy and, needing more facts, requests attributes through the context handler, which queries the Policy Information Point and returns subject, resource, and environment attributes. The decision point evaluates the policy against the request and attributes, then returns permit or deny to the context handler, which passes it to the enforcement point. Finally the enforcement point either allows or blocks Sara's access. The administration step is separated in time from the live request flow. participant U as Sara participant PEP as PEP (Doorkeeper) participant CH as Context handler participant PDP as PDP (Manager) participant PIP as PIP (Clerk) participant PAP as PAP (Owner) PAP-->>PDP: publish policies (setup, before the request) U->>PEP: request access PEP->>CH: forward request CH->>PDP: decide? PDP->>CH: need attributes CH->>PIP: fetch subject / resource / environment PIP-->>CH: attributes CH-->>PDP: attributes PDP->>PDP: evaluate policy PDP-->>CH: permit / deny CH-->>PEP: permit / deny PEP-->>U: allow or block
Ahead of time, the owner publishes the rules to the manager; that dashed setup step is the only part that doesn’t happen during Sara’s request. Then Sara asks the doorkeeper to let her in. He doesn’t reason about it; he passes the request to the manager’s assistant, who asks the manager to decide. The manager pulls up the relevant rule, sees she needs facts, and asks for Sara’s attributes; the assistant fetches them from the clerk and brings them back. The manager evaluates the rule against the request and the facts, produces permit or deny, and sends it back to the doorkeeper, who opens or blocks the door. Each component did one job, and the request touched each in turn.
Why split it into four?
It can look like bureaucracy. Why not let one component do everything? Because the separation buys properties you can’t get any other way, the same benefits the PBAC article promised, now with a concrete structure.
Because deciding is separate from enforcing, one PDP can serve dozens of PEPs. Every application, service, and gateway asks the same manager, so they all enforce the same rules identically, and consistency becomes a property of the architecture rather than a hope. Because writing rules is separate from deciding and enforcing, the owner can rewrite the house rules and every decision changes at once, with no PEP redeployed. Because information is separate from decision, you can add an attribute source, a risk feed or a new directory, without touching the policy logic or the enforcement code. And because every decision flows through the PDP, there’s one place to log who asked for what and what was decided, instead of reconstructing it from scattered application logs. Each seam lets one concern change without disturbing the others, which is what keeps large authorization systems maintainable.
What the PDP evaluates
We’ve treated “the rules” as a black box. XACML also gave them a precise structure, the same anatomy the PBAC article described, now named formally. A rule is the smallest unit: a target saying which requests it applies to, an optional condition for a finer test, and an effect, Permit or Deny. In the club, “gold members may enter” is a rule. A policy is a named group of rules about one area with its own combining algorithm, like the membership section of the rulebook. A policy set groups policies, and other policy sets, again with a combining algorithm, like the whole rulebook divided into chapters.
A request reaching the PDP is structured too. It describes the subject (who), the resource (what), the action (which operation), and the environment (the context), the same four attribute categories the ABAC article introduced. The PDP matches the request against the targets in the policy tree to find which rules apply, evaluates their conditions against the attributes, and folds the results together. Here’s one request and one rule in readable pseudo-form, stripped of XACML’s real XML, which would be many times longer:
REQUEST RULE (effect: Permit)
subject.role = "support-agent" target: action == "view"
action = "view" resource.type == "account"
resource.type = "account" condition: subject.role == "support-agent"
resource.id = 4471 AND ticket.open_for(resource) == true
environment.time = 14:30 AND environment.time in business_hoursThe target is the cheap filter that decides whether the rule is even relevant, and it is, because the action is view on an account. The condition is the finer test against the gathered attributes: is the role right, is there an open ticket, is it working hours? The effect is what happens if both pass, Permit. Every rule in every engine has these three parts, however different the syntax, which is why learning the shape matters more than learning a language. It also raises the question that makes multi-rule policies work: what happens when two rules both match and disagree?
Combining algorithms: settling disagreements
As soon as you have more than one rule, two can match the same request and disagree, one permitting and the other denying. XACML’s answer is the combining algorithm, a declared, deterministic way of folding many partial decisions into one. Every policy and policy set has one, and it decides how conflicts and gaps resolve.
| Combining algorithm | Rule | When you want it |
|---|---|---|
| deny-overrides | Any Deny wins, whatever the Permits | The safe default: one prohibition beats every grant |
| permit-overrides | Any Permit wins, whatever the Denies | When any grant should be enough |
| first-applicable | The first matching rule, in order, decides | When rule order expresses priority |
| only-one-applicable | Error unless exactly one rule matches | When overlap itself is a bug to catch |
This isn’t a footnote; it’s a real security decision. Deny-overrides is the conservative choice, guaranteeing that if any rule refuses, access is refused, so a forgotten grant never quietly opens something a deny meant to close. Choosing permit-overrides flips that safety, and first-applicable makes the order of rules meaningful in ways that can surprise you. When you evaluate a policy engine, one of the first questions is what its default combining behavior is and whether you can reason about what happens in the gaps, because that behavior, not any single rule, governs the whole.
The decision isn’t just yes or no
A XACML PDP returns one of four values, not a boolean, and collapsing them too early is a classic source of bugs. Permit means access is allowed: let her in. Deny means it’s refused: turn her away. NotApplicable means no policy matched the request at all: no rule covers this situation. Indeterminate means evaluation failed, for example because an attribute was missing: the clerk couldn’t find her file.
Each needs different handling. NotApplicable means the PDP has no opinion, and the PEP has to decide how to treat silence, which for security should almost always be deny by default, because a gap isn’t permission. Indeterminate means something broke, the PIP couldn’t supply a required attribute or a policy errored. Treating it as a plain deny can hide an outage or a misconfiguration that deserves an alert, and treating it as permit is a security hole. A mature system tells apart “no rule applied,” “a rule denied,” and “evaluation failed,” and handles each on purpose. Along with the decision, the PDP may also return obligations and advice, the “permit, but log it” and “permit, and show a notice” extras from the PBAC article, which the PEP has to carry out.
The most dangerous shortcut is to reduce every non-Permit to one “deny” and move on. It usually works, which is what makes it dangerous, until the day an attribute source goes down, every request comes back Indeterminate, and your blanket “treat as deny” turns a data outage into a total lockout with no alert, or, if you chose “treat as permit for availability,” into an open door. Decide deliberately what NotApplicable and Indeterminate mean in your system, make default-deny explicit, and alert on Indeterminate instead of swallowing it.
The language faded, the architecture won
XACML shipped two things: an XML language for writing policies and the four-part architecture for evaluating them. History treated them very differently. The language was powerful but notoriously verbose, so that a rule taking one line of Rego could sprawl over dozens of lines of nested XML, and it never won developers over; new systems almost never write raw XACML today. The architecture was a quiet triumph. The separation of PEP, PDP, PIP, and PAP, the request and decision flow, combining algorithms, obligations, the four decision values: these became the conceptual foundation of essentially every authorization engine built since.
You’ve met the pattern already under other names. The PBAC article introduced the enforcement and decision points and described OPA, Cedar, and hosted authorization services as “a PEP asks, a PDP decides against externalized policy, data flows in from sources.” That is the XACML architecture; those articles were teaching it before naming it. Open Policy Agent is a PDP you run yourself, your app’s OPA client is the PEP, the data you load into OPA plays the PIP, and your Rego repository and CI pipeline are the PAP. Amazon Verified Permissions is a managed PDP that speaks Cedar. Once you see the four roles, every product sorts itself into them, and learning a new authorization tool becomes a matter of working out which of the four roles it plays and how.
Where the components live
The architecture is deliberately silent about deployment, and real systems place the PDP in three broadly different ways, a choice with real consequences for latency, freshness, and blast radius that the decentralized authorization article develops in full. The PDP can be a library compiled into the application, which is fastest, with no network hop, but leaves a copy per app to keep in sync. It can be a sidecar running next to each service, local and fast and decoupled from the app’s code, the common cloud-native pattern, as with OPA as a sidecar. Or it can be a central service every app calls over the network, one authoritative decider but a network dependency on the request path and one more thing to keep highly available. The PEP is almost always in the application or its gateway, because enforcement has to happen where the action does; the PAP is usually a separate authoring and CI system; and the PIPs are wherever your attributes already live. There’s no universally right placement, only trade-offs among speed, consistency, and coupling. The four roles are logical, not physical: they can collapse into one process or spread across a continent, and recognizing them means spotting the four jobs, not four separate servers.
Sara at the cashback app
Swap the club for the cashback fintech and the mapping holds exactly. Sara, now a support agent, opens the console and clicks to view customer account #4471. The console’s PEP intercepts the click and, instead of deciding anything, packages a request, subject Sara with role support-agent, action view, resource account #4471, and sends it to the PDP. The PDP loads the policy the security team wrote through the PAP: a support agent may view an account only with an open ticket assigned for it, during working hours. Needing facts, the PDP asks for attributes, and the PIPs supply Sara’s role and shift from the directory, the ticket system’s record that ticket #90210 is open and assigned to Sara for this customer, and the current time. The PDP evaluates the rule, gets Permit, and returns it with an obligation to log the access. The PEP writes the audit entry and shows the account. Run the same flow after hours and it returns Deny, and the same PEP blocks the view.
Look at what this buys the fintech. The same policy governs the mobile app, the web console, and tomorrow’s fraud-review tool, because each needs only a PEP that asks the shared PDP. When compliance tightens the rule, the security team edits it once at the PAP and every surface obeys within seconds, with no app redeployed. When a new attribute matters, say a device-risk score, it’s added at a PIP without touching a line of policy or enforcement code. The architecture didn’t just answer Sara’s request; it made the whole system changeable, which at scale matters even more than any single decision.
Recap
The XACML reference architecture is the blueprint underneath nearly every authorization system. It has four roles, cleanly separated: the PEP asks and enforces, the PDP decides, the PIP supplies facts, and the PAP writes the rules ahead of time, with a context handler carrying requests and attributes between them. A request moves through them in order: the PEP forwards it, the PDP evaluates the policy published earlier through the PAP, pulls attributes from PIPs as needed, and returns a decision the PEP enforces. The separation is the payoff: one decider serves many enforcers consistently, rules change without redeploying apps, data sources change freely, and every decision is audited in one place. Policies are structured as rules with a target, condition, and effect, inside policies inside policy sets, with combining algorithms settling conflicts, a real security choice, and decisions come in four values rather than a bare boolean. And the XML language faded while the architecture won everywhere: OPA, Cedar, Verified Permissions, and cloud IAM all follow this pattern.
Three questions to test yourself
- Using the club, explain the difference between the PEP and the PDP, and separately between the PIP and the PAP. For each pair, give the one-sentence tell that keeps them apart.
- A request arrives, two rules match, one permits and one denies, and the policy uses deny-overrides. What’s the result, and why is the choice of combining algorithm a security decision rather than a technical detail? What would change under first-applicable?
- A PDP returns Indeterminate because a PIP couldn’t supply a required attribute. Explain why collapsing that to deny can be dangerous, why collapsing it to permit is worse, and what a mature PEP should do with NotApplicable compared with Indeterminate.
Hands-on exercises
- Map a system you use to the four roles. Pick a platform with externalized authorization, such as Kubernetes with OPA Gatekeeper, a service mesh, or a cloud authorization service. Identify what plays the PEP, the PDP, the PIP, and the PAP, and where the policy is stored. If a role is missing or merged into another, note it; that tells you something about the system’s trade-offs.
- Trace a request on paper. Take the cashback rule (a support agent may view an account only with an open assigned ticket, during working hours) and write out the ordered messages between PEP, context handler, PDP, PIP, and PAP for one Permit case and one Deny case. Mark which step happens at setup and which at request time.
- Choose combining algorithms on purpose. Write three plain-language rules for a resource where at least two can apply to the same request, then work out the outcome under deny-overrides, permit-overrides, and first-applicable. Note where they disagree; that gap is exactly the security decision the combining algorithm makes for you.
Frequently asked questions
What are the PEP, PDP, PIP, and PAP in XACML?
They're the four components of the XACML reference architecture, and each has one job. The policy enforcement point (PEP) sits in the application, intercepts the access request, asks for a decision, and enforces it; it guards the door but doesn't decide. The policy decision point (PDP) is the engine that evaluates policy against the request and returns permit or deny; it's the actual decision-maker. The policy information point (PIP) supplies the extra attributes the PDP needs, such as user details, resource metadata, and environment facts, from directories, databases, or services. The policy administration point (PAP) is where policies are written and managed, ahead of time. Separating who enforces, who decides, who informs, and who authors is the whole point of the model.
What is the difference between a PEP and a PDP?
The PEP enforces; the PDP decides. The policy enforcement point is code in an application that intercepts a request, packages it as an authorization query, sends it to the decision engine, and acts on the answer by allowing or blocking the operation. It has no policy logic of its own. The policy decision point is the separate engine that holds the policies, evaluates them against the request and any attributes gathered for it, and returns a decision. Keeping them apart means one central decision-maker can serve many enforcement points consistently, and the rules can change without touching the applications that enforce them.
Is XACML still used today?
The XACML XML language itself is largely legacy: verbose and little loved, it has been replaced for new work by lighter policy languages like Rego (OPA) and Cedar. But the XACML reference architecture, the separation of PEP, PDP, PIP, and PAP and the request and decision flow, won completely and is alive everywhere. Almost every modern authorization engine, whatever its language, is a recognizable implementation of that four-part pattern. So learn XACML for its architecture, which is foundational and universal, not for its syntax, which you'll rarely write.
What is a combining algorithm in XACML?
A combining algorithm decides the final result when several rules or policies apply to the same request and disagree. A real policy set holds many rules, two of them can match at once with one permitting and the other denying, so the engine needs a deterministic way to settle the conflict. The common algorithms are deny-overrides (any deny wins, the safe default), permit-overrides (any permit wins), first-applicable (the first matching rule decides), and only-one-applicable. Choosing one is a real security decision, because it determines what happens in the gaps and conflicts between rules.
What are the four XACML decision values?
A XACML decision isn't a bare yes or no; it's one of four values. Permit means access is allowed. Deny means it's refused. NotApplicable means no policy matched the request, so the engine has no opinion and the PEP must decide how to treat that, usually as a deny. Indeterminate means an error prevented a clean evaluation, such as a missing attribute the PDP needed. Telling 'no rule applied' from 'a rule denied' from 'evaluation failed' matters, because each needs different handling, and a system that collapses them all into 'deny' can hide real problems.