DAY 08 WEEK 2: CORE SERVICES

Policy Decision Point (PDP) - Concepts

Understand AuthZEN 1.1 specification, policy structure, YAML syntax, and the 5-level inheritance hierarchy.

Authentication tells you who someone is. But knowing who someone is doesn't tell you what they're allowed to do. That's authorizationโ€”and it's surprisingly complex. Can Alice read this document? Can Bob delete that order? Can the Scheduler Service access the reporting API at 3am? The Policy Decision Point (PDP) is the brain that answers these questions, and today you'll learn how it thinks.

๐Ÿ“‹Learning Objectives

  • Understand what a PDP does and why it matters
  • Learn the AuthZEN 1.1 specification basics
  • Understand policy structure: applications, resources, actions
  • Master YAML policy syntax and JSON policy format (IGA)
  • Know the four IGA policy categories: guardrails, SoD, birthright, temporal
  • Understand pdp_application routing and rich decision context
  • Understand the 5-level inheritance hierarchy

๐ŸŽฏWhat is a Policy Decision Point?

Imagine you're a bouncer at a VIP club. Someone shows you their ID (authentication). But knowing they're "John Smith" doesn't tell you if they're on the guest list, if their membership is active, or if they're allowed in the VIP section. You need a policy to make that decision. The PDP is that bouncerโ€”for every API call, database query, and button click in your application.

The PDP is the brain of the authorization system. It answers the question:

"Can Subject perform Action on Resource?"

Key Concepts

  • Subject: Who is making the request (user, service, role)
  • Action: What operation they want to perform (read, write, delete)
  • Resource: What they want to access (document, API endpoint, feature)
  • Context: Additional attributes (time, location, device)
PDP Authorization Flow
flowchart TB subgraph Request["๐Ÿ“ฅ Authorization Request"] S["๐Ÿ‘ค Subject
(User)"] A["โšก Action
(Read)"] R["๐Ÿ“„ Resource
(Document)"] end S --> PDP A --> PDP R --> PDP PDP["๐Ÿง  PDP
Policy Evaluation"] PDP --> D{Decision} D -->|"โœ…"| PERMIT["โœ… PERMIT
Access Granted"] D -->|"โŒ"| DENY["โŒ DENY
Access Denied"] style PDP fill:#7c3aed,color:#fff style PERMIT fill:#059669,color:#fff style DENY fill:#e11d48,color:#fff

๐Ÿ“œAuthZEN 1.1 Specification

Just like OAuth standardized authentication APIs, AuthZEN standardizes authorization APIs. Instead of every vendor inventing their own way to ask "is this allowed?", AuthZEN defines a common language. This means you can swap PDPs without rewriting your applicationโ€”and your skills transfer across organizations.

EmpowerNow PDP implements the AuthZEN 1.1 specification, a standard for authorization APIs:

Standard Endpoints

EndpointMethodPurpose
/access/v1/evaluationPOSTSingle authorization decision
/access/v1/evaluationsPOSTBatch authorization decisions
/access/v1/searchPOSTSearch for allowed resources/actions

Standard Request Format

{
  "subject": {
    "type": "user",
    "id": "user-uuid-123",
    "properties": {
      "department": "engineering"
    }
  },
  "action": {
    "name": "read"
  },
  "resource": {
    "type": "document",
    "id": "doc-456",
    "properties": {
      "classification": "confidential"
    }
  },
  "context": {
    "time": "2024-01-15T10:30:00Z",
    "ip_address": "192.168.1.100"
  }
}

Standard Response Format

{
  "decision": true,           // or false
  "context": {
    "reason_admin": {
      "explanation": "User has 'reader' role on document"
    }
  }
}
๐Ÿงช Try It: Make an Authorization Request Interactive

Copy curl and run in your terminal to ask the PDP: "Can user Alice read the products catalog?" This is a real AuthZEN evaluation request!

โœ… What to Expect

You should see "decision": true because reading products is allowed for all users in the it-shop application.

๐Ÿšซ Try It: A Denied Request Interactive

Copy curl and run in your terminal to try something that should be deniedโ€”deleting products without admin role:

โœ… What to Expect

You should see "decision": false because only users with the product-admin role can delete products.

๐Ÿš€The Authorization Request Journey

Let's follow an authorization request from start to finish. When your API receives a request, what happens behind the scenes? Understanding this flow will help you debug authorization failures and optimize performance.
Complete Authorization Flow
sequenceDiagram participant User as ๐Ÿ‘ค User participant API as ๐ŸŒ API Gateway participant PDP as ๐Ÿง  PDP participant Cache as โšก Redis Cache participant Policies as ๐Ÿ“ Policy Store participant PIPs as ๐Ÿ”Œ PIPs User->>API: GET /products/123 API->>API: Extract JWT claims Note over API,PDP: Build AuthZEN Request API->>PDP: POST /access/v1/evaluation PDP->>Cache: Check decision cache alt Cache Hit Cache-->>PDP: Cached decision else Cache Miss PDP->>Policies: Load applicable policies Policies-->>PDP: Policy rules PDP->>PIPs: Fetch additional attributes PIPs-->>PDP: User roles, resource metadata PDP->>PDP: Evaluate rules PDP->>Cache: Store decision end PDP-->>API: {"decision": true/false} alt Decision = true API-->>User: 200 OK + Data else Decision = false API-->>User: 403 Forbidden end

Step-by-Step Breakdown

  1. Request Arrives: User makes an API request with their JWT access token
  2. Extract Context: API extracts user ID, roles, and request details from the JWT and request
  3. Build AuthZEN Request: API constructs the subject/action/resource/context JSON
  4. Cache Check: PDP checks if this exact decision was recently made
  5. Policy Loading: On cache miss, PDP loads policies for the application and resource type
  6. Attribute Enrichment: Policy Information Points (PIPs) fetch additional data if needed
  7. Rule Evaluation: PDP evaluates rules in order, applying inheritance
  8. Decision & Caching: Result is returned and cached for future requests
  9. API Response: API enforces the decisionโ€”either returning data or 403
โšก Performance Note

The cache check happens first because most authorization decisions are repetitive. A user accessing the same resource type multiple times will hit the cache after the first request, keeping latency under 1ms.

๐Ÿ“Policy Structure

Policies aren't thrown into a single giant fileโ€”they're organized like a well-structured codebase. Each application gets its own namespace, each resource type gets its own policy file, and inheritance keeps things DRY. Understanding this structure is essential before you start writing policies.

Policies are organized in a hierarchical structure:

Policy File Structure
flowchart TB subgraph Policies["๐Ÿ“ policies/"] subgraph Apps["๐Ÿ“ applications/"] subgraph ITShop["๐Ÿ“ it-shop/"] ITShopPolicy["๐Ÿ“„ principal-policy.json
Application principal policy"] end subgraph IGA["๐Ÿ“ identity-governance/"] PrincipalPolicy["๐Ÿ“„ principal-policy.json"] subgraph GuardrailsDir["๐Ÿ“ guardrails/"] GR["๐Ÿ“„ contractor-restrictions.json"] end subgraph SoDDir["๐Ÿ“ sod/"] SOD1["๐Ÿ“„ payment-vendor-sod.json"] SOD2["๐Ÿ“„ hr-payroll-sod.json"] end subgraph BirthrightDir["๐Ÿ“ birthright/"] BR["๐Ÿ“„ engineering-birthright.json"] end subgraph TemporalDir["๐Ÿ“ temporal/"] TEMP["๐Ÿ“„ contractor-expiration.json"] end end subgraph IdP["๐Ÿ“ idp/"] IdPPolicy["๐Ÿ“„ principal-policy.json"] end end subgraph Global["๐Ÿ“ global/"] BaseSec["๐Ÿ“„ base-security-policy.json
Global security baseline"] GlobalSec["๐Ÿ“„ global-security-baseline.json"] Recert["๐Ÿ“„ recertification-auto-policies.json"] end end style ITShopPolicy fill:#f59e0b,color:#000 style BaseSec fill:#7c3aed,color:#fff style PrincipalPolicy fill:#10b981,color:#fff style IdPPolicy fill:#3b82f6,color:#fff
๐Ÿ†• Identity Governance Application

The identity-governance PDP application organizes IGA policies into four categories: guardrails, SoD, birthright, and temporal. Each category has its own subdirectory and evaluates different resource types. Policies use JSON format with structured denyIf/allowIf conditions.

Application Scoping via pdp_application

Each application has its own policy namespace. The PDP determines which policy set to use via the resource.properties.pdp_application field:

{
  "resource": {
    "type": "group",
    "id": "IT-Admins",
    "properties": {
      "pdp_application": "identity-governance"
    }
  }
}
  1. PDP extracts pdp_application from resource.properties
  2. Resolves the application context from the registry
  3. Loads policies from the application's configured directories
  4. Applies the inheritance hierarchy and returns the decision
โš ๏ธ pdp_application Location

The pdp_application field lives inside resource.properties, not in context. Missing values default to "global". Invalid format returns HTTP 400; unknown application IDs return HTTP 422.

Example Application IDs

Application IDPurposePolicy Format
it-shopShopping features (cart, products, orders)JSON
identity-governanceIGA: guardrails, SoD, birthright, temporalJSON
experienceExperience app UI accessYAML
entraid-adminEntraID administrationYAML

๐Ÿ›ก๏ธIGA Policy Categories

Identity Governance takes PDP beyond "can user view this page?" into provisioning governance: "Can this contractor join an admin group? Does this role assignment create a fraud risk? What systems should a new hire get access to?" These are the four pillars of IGA policy enforcement.

๐Ÿšง Guardrails (GR-xxx)

"Can this provisioning action proceed?"

Resource types: iga.guardrail, group

Example: Contractors blocked from *-Admins groups

โš–๏ธ Separation of Duties (SOD-xxx)

"Does this role create a toxic combination?"

Resource types: iga.sod, role

Example: Payment approver + vendor manager = fraud risk

๐ŸŽ Birthright Provisioning (BR-xxx)

"What should a new hire automatically get?"

Resource types: iga.birthright, target_system

Example: Engineering FTE โ†’ EntraID + AD + OpenLDAP

โฑ๏ธ Temporal Constraints (TEMP-xxx)

"Is this access still valid in time?"

Resource types: iga.temporal

Example: Contractor expired, 4-hour emergency access

IGA Policy Evaluation Flow
sequenceDiagram participant Agent as ๐Ÿค– AI Agent / Workflow participant PDP as ๐Ÿง  PDP (identity-governance) participant MemberPIP as ๐Ÿ‘ฅ Membership PIP Agent->>PDP: CheckGuardrail (contractor โ†’ IT-Admins) PDP->>MemberPIP: Fetch employee_type MemberPIP-->>PDP: Contractor PDP-->>Agent: DENY + GR-001 (remediation, reason) Agent->>PDP: CheckSoD (payment_approver โ†’ vendor_manager) PDP-->>Agent: DENY + SOD-001 (toxic combination) Agent->>PDP: DiscoverBirthright (FTE, Engineering) PDP-->>Agent: PERMIT (av_entraid, av_ad, av_openldap)

IGA Resource Types

Resource TypeCategoryActions
iga.guardrailGuardrailsevaluate
iga.sodSeparation of Dutiesevaluate
iga.birthrightBirthright Provisioningevaluate
iga.temporalTemporal Constraintsevaluate
groupGuardrails targetadd_to_group
roleSoD targetacquire_role
target_systemBirthright targetbirthright_provision

๐Ÿ“YAML Policy Syntax

YAML is human-readable, which makes policies easier to review and audit than code. But with great readability comes great responsibilityโ€”indentation matters, and one typo can deny access to your entire user base. Let's learn the syntax that keeps your applications secure.

Policies are written in YAML with a specific schema:

Basic Policy Structure

# products.yaml - Policy for products resource
name: products
description: Access control for product catalog

rules:
  - id: allow-read-all
    description: Anyone can read products
    effect: permit
    subjects:
      - type: any
    actions:
      - read
      - list
    
  - id: allow-admin-write
    description: Admins can modify products
    effect: permit
    subjects:
      - type: role
        id: product-admin
    actions:
      - create
      - update
      - delete
    
  - id: deny-default
    description: Deny all other access
    effect: deny
    subjects:
      - type: any
    actions:
      - any

Conditions

rules:
  - id: allow-own-orders
    description: Users can only view their own orders
    effect: permit
    subjects:
      - type: user
    actions:
      - read
    conditions:
      - attribute: resource.owner_id
        operator: equals
        value: subject.id

Time-Based Conditions

rules:
  - id: business-hours-only
    description: Access only during business hours
    effect: permit
    conditions:
      - attribute: context.time
        operator: time_between
        value:
          start: "09:00"
          end: "17:00"
          timezone: "America/New_York"

๐Ÿ”„JSON Policy Format (IGA Policies)

While standard resource policies use YAML, the IGA policies use a JSON-based format with structured conditions. This format makes policies machine-readable for agent workflows while staying auditor-friendly. The key difference: instead of listing subjects and actions, JSON policies use denyIf / allowIf blocks with condition arrays.

YAML vs JSON: Side by Side

YAML (Traditional โ€” it-shop)

# products.yaml
rules:
  - id: allow-read-all
    effect: permit
    subjects:
      - type: any
    actions:
      - read

JSON (IGA โ€” identity-governance)

{
  "id": "GR-001-contractor-no-admin",
  "effect": "DENY",
  "denyIf": {
    "operator": "AND",
    "conditions": [
      {"scope": "subject",
       "attribute": "properties.employee_type",
       "operator": "equals",
       "value": "Contractor"},
      {"scope": "resource",
       "attribute": "properties.name",
       "operator": "matches",
       "value": ".*-Admins?$"}
    ]
  }
}

JSON Condition Structure

Each condition in a denyIf or allowIf block has four fields:

FieldPurposeExamples
scopeWhere to look for the attributesubject, resource, context
attributeDotted path to the valueproperties.employee_type, id
operatorComparison to performequals, in, matches, contains_any, after_date
valueExpected value or pattern"Contractor", ["admin", "editor"], ".*-Admins?$"

Complete IGA Policy Example (GR-001)

{
  "id": "GR-001-contractor-no-admin-groups",
  "effect": "DENY",
  "denyIf": {
    "operator": "AND",
    "conditions": [
      {"scope": "subject", "attribute": "properties.employee_type",
       "operator": "equals", "value": "Contractor"},
      {"scope": "resource", "attribute": "properties.name",
       "operator": "matches", "value": ".*-Admins?$"}
    ]
  },
  // Rich context returned with the DENY decision
  "on_deny": {
    "context": {
      "guardrail_id": "GR-001",
      "reason_user": {"en": "Contractors cannot be added to admin groups"},
      "reason_admin": {"en": "GR-001: Contractor attempted to join admin group"},
      "remediation": "Remove admin group request or convert contractor to FTE"
    }
  }
}
๐Ÿ’ก on_deny vs on_permit

on_deny.context is returned when the policy blocks access โ€” it carries the reason, remediation steps, and guardrail/SoD IDs for auditing.

on_permit.context is returned when access is allowed โ€” for birthright policies it carries what to provision (groups, attributes, licenses).

๐Ÿ—๏ธ5-Level Inheritance Hierarchy

Writing the same "deny all by default" rule in 50 different files is madness. The 5-level inheritance hierarchy lets you define policies at the right level of granularityโ€”from global defaults that protect everything, down to specific rules for individual documents. It's like CSS specificity, but for security.

Policies inherit from multiple levels, allowing for flexible and DRY configurations:

5-Level Policy Inheritance
flowchart TB L1["๐ŸŒ Level 1: Global Default
All applications"] L2["๐Ÿข Level 2: Application Default
Single app scope"] L3["๐Ÿ“ฆ Level 3: Resource Type
Type of resource"] L4["โšก Level 4: Action
Specific action"] L5["๐ŸŽฏ Level 5: Instance
Specific resource"] L1 --> L2 --> L3 --> L4 --> L5 style L1 fill:#7c3aed,color:#fff style L2 fill:#3b82f6,color:#fff style L3 fill:#0891b2,color:#fff style L4 fill:#059669,color:#fff style L5 fill:#f59e0b,color:#000
LevelScopeExample
1. GlobalAll applicationsDeny access to blocked users
2. ApplicationSingle appIT Shop requires authentication
3. Resource TypeType of resourceDocuments require classification
4. ActionSpecific actionDelete requires approval
5. InstanceSpecific resourceThis document requires manager role

Inheritance Example

// Level 2: Application default (principal-policy.json)
{
  "schema_version": "2.0",
  "application": "it-shop",
  "rules": [...]  // Application-scoped rules
}

# Level 3: Resource type (scoped via resource.type in rules)
name: products
inherit: true  # Inherit from application level
rules:
  - id: public-read
    effect: permit
    actions: [read]
    subjects:
      - type: any
๐Ÿ’ก Best Practice

Start with restrictive global defaults (deny), then open up access at lower levels. This follows the principle of least privilege.

๐Ÿ”ฌHands-on Labs

Theory is great, but nothing beats looking at real policies and making real authorization requests. These labs will give you hands-on experience with the PDP that you'll use tomorrow when writing your own policies.
LAB 1 Explore the Policy Directory โฑ๏ธ 5 minutes

Let's explore the actual policy files that power the EmpowerNow platform.

1

Navigate to the policy directory: (replace <YourRepoRoot> with your project root, e.g. EmpowerNow)

# Windows (PowerShell)
cd <YourRepoRoot>\ServiceConfigs\Deployment\config\pdp\policies

# macOS/Linux
cd <YourRepoRoot>/ServiceConfigs/Deployment/config/pdp/policies
2

List the applications with policies:

# Windows
dir applications

# macOS/Linux
ls applications

You should see folders like it-shop, identity-governance, idp, etc.

3

Read an application-level policy:

# Windows
type applications\it-shop\principal-policy.json

# macOS/Linux
cat applications/it-shop/principal-policy.json
4

Explore the IGA application policies:

# Windows
dir applications\identity-governance
type applications\identity-governance\principal-policy.json

# macOS/Linux
ls applications/identity-governance
cat applications/identity-governance/principal-policy.json
โœ… Expected Findings
  • principal-policy.json defines application-level rules using JSON IR schema
  • IGA subdirectories (guardrails/, sod/, etc.) contain category-specific policies
  • Each rule has an id, effect, conditions via $expr, and optional on_deny/on_permit context
๐Ÿค” Self-Check
  • What is the default effect for the it-shop application?
  • Which roles can modify products?
  • Are there any conditions defined in the policies?
LAB 2 Make AuthZEN Requests with curl โฑ๏ธ 10 minutes

Let's make authorization requests directly to the PDP using curl.

1

Check if PDP is healthy:

curl -s https://pdp.self.empowernow.ai/health | jq .
2

Make a permit request (reading products):

curl -s -X POST https://pdp.self.empowernow.ai/access/v1/evaluation \
  -H "Content-Type: application/json" \
  -d '{
    "subject": {"type": "user", "id": "alice"},
    "action": {"name": "read"},
    "resource": {"type": "products", "id": "catalog"},
    "context": {"application": "it-shop"}
  }' | jq .
3

Make a deny request (deleting without permission):

curl -s -X POST https://pdp.self.empowernow.ai/access/v1/evaluation \
  -H "Content-Type: application/json" \
  -d '{
    "subject": {"type": "user", "id": "alice"},
    "action": {"name": "delete"},
    "resource": {"type": "products", "id": "product-123"},
    "context": {"application": "it-shop"}
  }' | jq .
4

Try a batch evaluation:

curl -s -X POST https://pdp.self.empowernow.ai/access/v1/evaluations \
  -H "Content-Type: application/json" \
  -d '{
    "evaluations": [
      {
        "subject": {"type": "user", "id": "alice"},
        "action": {"name": "read"},
        "resource": {"type": "products"},
        "context": {"application": "it-shop"}
      },
      {
        "subject": {"type": "user", "id": "alice"},
        "action": {"name": "write"},
        "resource": {"type": "orders"},
        "context": {"application": "it-shop"}
      }
    ]
  }' | jq .
โœ… Expected Output
  • Read products: {"decision": true}
  • Delete products: {"decision": false}
  • Batch: Array of decisions for each evaluation
๐Ÿค” Self-Check
  • What happens if you change the application context to one that doesn't exist?
  • How would you give Alice permission to delete products?
LAB 3 Understand Policy Inheritance โฑ๏ธ 10 minutes

Let's trace how policies inherit from each level.

1

Read the global security baseline (replace <YourRepoRoot> with your project root):

# Windows: type <YourRepoRoot>\serviceconfigs\pdp\config\policies\global\base-security-policy.json
# macOS/Linux: cat <YourRepoRoot>/serviceconfigs/pdp/config/policies/global/base-security-policy.json

This is Level 1โ€”applies to ALL applications.

2

Read the application default:

# Windows: type <YourRepoRoot>\serviceconfigs\pdp\config\policies\applications\it-shop\principal-policy.json
# macOS/Linux: cat <YourRepoRoot>/serviceconfigs/pdp/config/policies/applications/it-shop/principal-policy.json

This is Level 2โ€”applies to the it-shop application.

3

Read an IGA guardrail policy (resource type level):

# Windows: type <YourRepoRoot>\serviceconfigs\pdp\config\policies\applications\identity-governance\guardrails\contractor-restrictions.json
# macOS/Linux: cat <YourRepoRoot>/serviceconfigs/pdp/config/policies/applications/identity-governance/guardrails/contractor-restrictions.json

This is Level 3โ€”applies to the guardrail resource type within identity-governance.

4

Trace the inheritance:

  • Does the resource policy have inherit: true?
  • If a rule matches at Level 3, does Level 1 still apply?
  • What happens if Level 1 says deny but Level 3 says permit?
โœ… Key Insight

More specific policies (lower levels) override less specific ones (higher levels). A Level 3 permit can override a Level 2 deny, but not a Level 1 explicit deny. This is why "deny at the top" is a safe default.

๐Ÿ”งTroubleshooting Authorization

Authorization bugs are frustrating because they're often silent failuresโ€”no error message, just a 403. Here are the most common scenarios you'll encounter and how to debug them.
๐Ÿšซ The Unexpected 403 Case #1
๐Ÿ“‹ Symptom

User gets 403 Forbidden despite having the correct role. They could access this resource yesterday!

๐Ÿ” Investigation
  • Check if the user's role assignment is still valid (membership service)
  • Verify the application context is correct in the request
  • Look for recent policy changes that might have added restrictions
  • Check if there's a condition (time-based, IP-based) blocking access
# Get detailed decision explanation
curl -s -X POST https://pdp.self.empowernow.ai/access/v1/evaluation \
  -H "Content-Type: application/json" \
  -H "X-Debug: true" \
  -d '{"subject": {...}, "action": {...}, "resource": {...}}' | jq '.context.reason_admin'
โœ… Fix
  • Verify role assignment in membership: GET /users/{id}/roles
  • Check policy file for new conditions or rule changes
  • Clear the PDP cache if policy was recently updated
๐Ÿ“ The YAML Syntax Error Case #2
๐Ÿ“‹ Symptom

After editing a policy file, all authorization requests for that application return errors or unexpected denials.

๐Ÿ” Investigation
  • YAML is whitespace-sensitiveโ€”check indentation
  • Look for missing colons, quotes, or brackets
  • Verify the policy schema is correct (rules, subjects, actions)
# Validate YAML syntax
python -c "import yaml; yaml.safe_load(open('policy.yaml'))"

# Check PDP logs for parsing errors
docker logs pdp-app --tail 50 | grep -i error
โœ… Fix
  • Use a YAML validator or IDE with YAML support
  • Keep a backup before editing policies
  • Test policy changes in a development environment first
๐Ÿ”„ The Inheritance Confusion Case #3
๐Ÿ“‹ Symptom

A rule you added at the resource level isn't taking effect. The global or application level seems to be overriding it.

๐Ÿ” Investigation

Remember the inheritance rules:

  • More specific levels can permit where less specific levels deny
  • But explicit denies at higher levels may override lower permits
  • Check inherit: true in your policy file
โœ… Fix
  • Trace inheritance from Level 1 to Level 5 for your request
  • Use debug mode to see which rule matched
  • Consider if the rule should be at a different level

๐Ÿ“ฆRich Decision Context

A simple true/false isn't enough when a contractor is blocked from an admin group. The decision needs to explain why, suggest a fix, and optionally trigger automated actions. This is what on_deny.context, on_permit.context, and obligations provide.
Decision Response Anatomy
flowchart LR subgraph Decision["PDP Decision Response"] D["decision: true/false"] subgraph Ctx["context"] RU["reason_user
UI message"] RA["reason_admin
debug info"] GID["guardrail_id /
sod_violation"] REM["remediation
steps to fix"] end subgraph Oblig["obligations"] NOTIFY["alert_security"] REVOKE["auto_revoke_access
delay: 4h"] end end

Deny Response (Guardrail GR-001)

{
  "decision": false,
  "context": {
    "guardrail_id": "GR-001",
    "guardrail_name": "contractor_no_admin_groups",
    "risk_level": "high",
    "reason_user": {"en": "Contractors cannot be added to admin groups"},
    "reason_admin": {"en": "GR-001: Contractor attempted to join IT-Admins"},
    "remediation": "Remove admin group request or convert to FTE"
  }
}

Permit Response (Birthright BR-ENG-001)

{
  "decision": true,
  "context": {
    "naming_system": "av_entraid",
    "naming_object_type": "account",
    "birthright_groups": ["All-Employees", "Engineering-All"],
    "birthright_attributes": {"AccountEnabled": true, "UsageLocation": "US"},
    "licenses": ["Microsoft 365 E3"]
  }
}

Obligations (Automated Actions)

Some policies trigger automated side-effects alongside the decision:

"obligations": [
  {"type": "notification", "action": "alert_security",
   "parameters": {"priority": "high"}},
  {"type": "schedule", "action": "auto_revoke_access",
   "parameters": {"delay_hours": 4}}
]
Obligation TypeActionUse Case
notificationalert_securityEmergency access triggers SOC alert
scheduleauto_revoke_access4-hour auto-expiry for emergency grants
auditenhanced_loggingExtra logging for high-risk decisions

โ“Knowledge Check

Test your understanding before moving on. Click each question to reveal the answer.
1 What's the difference between authentication and authorization? โ–ผ

Authentication answers "Who are you?" It verifies identity through credentials, tokens, or certificates.

Authorization answers "What are you allowed to do?" It determines permissions based on policies, roles, and attributes.

You must authenticate before you can authorizeโ€”the PDP needs to know who's asking before it can decide if they're allowed.

2 What are the four components of an AuthZEN request? โ–ผ
  1. Subject: Who is making the request (user, service, role)
  2. Action: What operation they want to perform (read, write, delete)
  3. Resource: What they want to access (document, API, feature)
  4. Context: Additional attributes (time, IP, application)
3 What are the 5 levels of the policy inheritance hierarchy? โ–ผ
  1. Global: Applies to all applications
  2. Application: Applies to a single application
  3. Resource Type: Applies to a type of resource (e.g., all products)
  4. Action: Applies to a specific action (e.g., delete)
  5. Instance: Applies to a specific resource (e.g., product-123)

More specific levels override less specific ones.

4 Why is "default deny" a best practice? โ–ผ

Default deny means: "If no rule explicitly permits this action, deny it."

This follows the principle of least privilegeโ€”users only get access they've been explicitly granted. It's safer than default permit because:

  • New resources are protected by default
  • Forgetting to write a policy doesn't create a security hole
  • You have to consciously decide to grant access
5 What are Policy Information Points (PIPs)? โ–ผ

PIPs are external data sources that the PDP queries to make decisions. When a policy needs information not in the request, it asks a PIP.

Examples:

  • Membership service: "What roles does this user have?"
  • Resource metadata service: "Who owns this document?"
  • Time service: "What's the current time in the user's timezone?"
6 What's the difference between /evaluation and /evaluations endpoints? โ–ผ

/access/v1/evaluation (singular): Evaluates a single authorization request. Returns one decision.

/access/v1/evaluations (plural): Evaluates multiple requests in a single call. Returns an array of decisions.

Use batch evaluation when checking multiple permissions at once (e.g., "What can this user do on this page?") to reduce network overhead.

7 Why does the PDP cache decisions? โ–ผ

Authorization decisions are evaluated on nearly every API request. Without caching, the PDP would become a bottleneck.

Caching works because:

  • Most requests are repetitive (same user, same resource type)
  • Policies change infrequently
  • Cache can be invalidated when policies update

With caching, repeat decisions return in <1ms instead of 10-50ms.

8 What are the four IGA policy categories? โ–ผ
  1. Guardrails (GR-xxx): Pre-provisioning checks that block or allow actions (e.g., contractors can't join admin groups)
  2. Separation of Duties (SOD-xxx): Detect toxic role combinations before assignment (e.g., payment approver + vendor manager)
  3. Birthright (BR-xxx): Discover what systems/groups to provision based on HR attributes (e.g., Engineering FTE gets EntraID + AD + OpenLDAP)
  4. Temporal (TEMP-xxx): Time-based constraints (e.g., contractor expired, max access duration)
9 Where does pdp_application go in an AuthZEN request? โ–ผ

The pdp_application field goes inside resource.properties:

"resource": {
  "type": "group",
  "id": "IT-Admins",
  "properties": {
    "pdp_application": "identity-governance"
  }
}

This tells the PDP which application's policy set to load. Missing values default to "global". Invalid format returns HTTP 400; unknown application IDs return HTTP 422.

10 What is on_deny.context used for? โ–ผ

on_deny.context provides rich metadata returned alongside a deny decision. It typically includes:

  • guardrail_id / sod_violation: The rule ID that triggered the deny
  • reason_user: A user-friendly explanation for the UI
  • reason_admin: Technical details for debugging
  • remediation: Steps to resolve the denial

Similarly, on_permit.context returns metadata for allowed actions โ€” for birthright policies this includes which groups and attributes to provision.

๐Ÿ“Day 8 Checkpoint

  • Can explain what a PDP does and its role in authorization
  • Understand the AuthZEN request/response format
  • Know the policy file structure and organization
  • Can read and understand YAML policy syntax
  • Know the JSON policy format used by IGA policies
  • Can name the four IGA policy categories and their resource types
  • Understand pdp_application and rich decision context
  • Understand the 5-level inheritance hierarchy
๐Ÿ’ก Want to Write Your Own Policies?

For hands-on PDP policy authoring, JSON IR, and application registration patterns, use the official EmpowerNow documentation together with your platform administrator.