OpenID AuthZEN policy backend for Microsoft Agent Governance Toolkit
Project description
authzen-policy-backend
OpenID AuthZEN policy backend for the Microsoft Agent Governance Toolkit.
Connect any AuthZEN-compliant Policy Decision Point (PDP) to Microsoft's Agent Governance Toolkit as a pluggable ExternalPolicyBackend — with one add_backend() call.
┌────────────────────────────────────────────────────────────────┐
│ Your AI Agent │
│ (LangGraph, OpenAI Agents, AutoGen, custom, ...) │
└──────────────────────┬─────────────────────────────────────────┘
│ evaluate(context)
┌──────────────────────▼─────────────────────────────────────────┐
│ MS Agent Governance Toolkit │
│ PolicyEvaluator → YAML rules (fast local) │
│ → AuthZENBackend (this package) │
└──────────────────────┬─────────────────────────────────────────┘
│ POST /access/v1/evaluation
┌──────────────────────▼─────────────────────────────────────────┐
│ AuthZEN PDP │
│ (EmpowerNow ARIA, Cerbos, Aserto, or any compliant PDP) │
│ → Obligations, Constraints, Advice, Delegation, Budget │
└────────────────────────────────────────────────────────────────┘
Why
The Agent Governance Toolkit provides in-process YAML policy evaluation and optional OPA/Cedar backends. For enterprise deployments, you need:
- Centralized policy management — one PDP governs all agents, not scattered YAML files
- Standards-based authorization — OpenID AuthZEN, not proprietary policy formats
- Rich decisions — obligations, constraints, budget limits, and denial advice beyond binary allow/deny
- Delegation-aware identity — user-bound agents with scoped capabilities
- Audit-grade decisions — decision IDs that link to cryptographic receipts
This package bridges that gap with a single add_backend() call.
Installation
pip install authzen-policy-backend
Quick Start
Minimal — 3 Lines to Policy Evaluation
from agent_os.policies import PolicyEvaluator
from authzen_backend import AuthZENBackend
evaluator = PolicyEvaluator()
evaluator.add_backend(AuthZENBackend(
pdp_url="https://pdp.example.com/access/v1/evaluation",
pdp_application="my-agent-platform",
token="my-bearer-token",
))
decision = evaluator.evaluate({
"tool_name": "file_read",
"agent_id": "travel-agent-1",
"user_id": "alice",
})
print(decision.allowed) # True / False
print(decision.reason) # Human-readable reason from PDP
print(decision.evaluation_ms) # Round-trip time in ms
Client Credentials — Production Auth
from authzen_backend import AuthZENBackend, ClientCredentialsAuth
backend = AuthZENBackend(
pdp_url="https://pdp.example.com/access/v1/evaluation",
pdp_application="my-agent-platform",
client_credentials=ClientCredentialsAuth(
token_endpoint="https://idp.example.com/oauth/token",
client_id="agent-policy-client",
client_secret="...",
audience="pdp",
),
)
# Tokens are cached and refreshed automatically
decision = backend.evaluate({
"tool_name": "transfer_funds",
"agent_id": "finance-bot",
"user_id": "bob",
})
Async Backend — For Async Agent Runtimes
from authzen_backend import AsyncAuthZENBackend
async with AsyncAuthZENBackend(
pdp_url="https://pdp.example.com/access/v1/evaluation",
pdp_application="my-agent-platform",
token="my-bearer-token",
) as backend:
result = await backend.evaluate({
"tool_name": "deploy_service",
"agent_id": "ops-agent",
})
ARIA-Enhanced Context — Obligations, Constraints, Advice
When connected to an EmpowerNow ARIA PDP, extract rich governance context that generic AuthZEN backends don't provide:
from authzen_backend import AuthZENBackend
from authzen_backend.aria import extract_aria_context
backend = AuthZENBackend(
pdp_url="https://aria-pdp.example.com/access/v1/evaluation",
pdp_application="my-platform",
token="...",
)
result = backend.evaluate({
"tool_name": "transfer_funds",
"agent_id": "finance-bot",
"user_id": "bob",
"amount": 50000,
})
aria = extract_aria_context(result)
print(aria.decision_id) # Links to a signed receipt in Receipt Vault
print(aria.obligations) # Actions the caller must perform
print(aria.constraints) # Parameter-level restrictions
print(aria.advice) # Structured denial guidance with remediation
print(aria.requires_approval) # True if human-in-the-loop approval needed
How It Works
sequenceDiagram
participant Agent as Your Agent
participant PE as PolicyEvaluator
participant AZB as AuthZENBackend
participant PDP as AuthZEN PDP
Agent->>PE: evaluate(context)
PE->>AZB: evaluate(context)
Note over AZB: Map flat dict to<br/>AuthZEN 1.0 request
AZB->>PDP: POST /access/v1/evaluation
PDP-->>AZB: { decision, context }
Note over AZB: Extract reason,<br/>obligations, constraints
AZB-->>PE: BackendDecision
PE-->>Agent: Final decision
Context Mapping
The toolkit passes a flat dict to backends. This package maps it to a structured AuthZEN request:
| Toolkit Context Key | AuthZEN Field | Notes |
|---|---|---|
agent_id |
subject.id |
Normalized to ARN: auth:agent:agentmesh:{id} |
user_id |
subject.properties.bound_to_user_id |
User the agent acts for |
delegator |
subject.properties.delegator |
Delegation chain |
tool_name |
action.name, resource.id |
Also generates op:tool:{name} |
action |
action.name |
Overrides tool_name if present |
resource_type |
resource.type |
Defaults to mcp_tool |
resource_id |
resource.id |
Defaults to tool_name |
| (all others) | context.* |
Forwarded as-is |
context.pdp_application and action.properties.operation_ref_id are set automatically.
Custom Mapping
Override field names if your agents use different context keys:
from authzen_backend import AuthZENBackend, FieldMapping
backend = AuthZENBackend(
pdp_url="https://pdp.example.com/access/v1/evaluation",
pdp_application="my-platform",
token="...",
mapping=FieldMapping(
agent_id_key="principal",
tool_name_key="operation",
user_id_key="end_user",
),
)
Fail-Closed vs Fail-Open
flowchart TD
A[PDP call fails] --> B{fail_closed?}
B -->|"True (default)"| C["Return deny<br/>error = None"]
B -->|False| D["Return deny<br/>error = description"]
C --> E[Toolkit stops — hard deny]
D --> F[Toolkit tries next backend]
fail_closed=True(default): PDP errors produce an authoritative deny. The toolkit treats this as final and does not consult other backends. Use this for production.fail_closed=False: PDP errors set theerrorfield on theBackendDecision. The toolkit skips this backend and tries the next one, or falls back to its default action. Use this for multi-backend setups where another backend can decide.
Configuration Reference
| Parameter | Type | Default | Description |
|---|---|---|---|
pdp_url |
str |
(required) | AuthZEN evaluation endpoint URL |
pdp_application |
str |
(required) | Application ID for policy scoping |
token |
str |
None |
Static Bearer token (mutually exclusive with client_credentials) |
client_credentials |
ClientCredentialsAuth |
None |
OAuth client credentials config |
timeout |
float |
5.0 |
HTTP timeout in seconds |
default_resource_type |
str |
"mcp_tool" |
Fallback resource type |
default_subject_type |
str |
"ai_agent" |
Fallback subject type |
mapping |
FieldMapping |
DEFAULT_MAPPING |
Context field name overrides |
fail_closed |
bool |
True |
Hard deny on errors (True) or signal error (False) |
http_client |
httpx.Client |
None |
Inject a pre-configured HTTP client |
Security
- HTTPS enforced —
pdp_urlmust use HTTPS in production. HTTP is allowed only forlocalhost/127.0.0.1/[::1]during development. - Error sanitization —
httpxexceptions are reduced to safe descriptions (HTTP 503,PDP request timed out) so URLs, tokens, and response bodies are never leaked in logs or error messages. - No credential logging —
client_secretandtokenfields userepr=Falseso they never appear in logs, tracebacks, or__repr__output. - Injection protection —
extra_paramscannot override OAuth core fields (grant_type,client_id,client_secret).
See SECURITY.md for reporting vulnerabilities.
Testing
70 tests | 100% coverage | mypy strict | ruff
pip install -e ".[dev]"
pytest tests/ -v
ruff check src/ tests/
mypy src/
Compatibility
| Component | Version |
|---|---|
| Python | 3.10+ |
| Dependencies | httpx >=0.27, pydantic v2 |
| Agent Governance Toolkit | Any version with ExternalPolicyBackend |
| PDP | Any OpenID AuthZEN 1.0 compliant PDP |
This package has zero dependency on agent-os-kernel — it implements the ExternalPolicyBackend protocol structurally (duck typing). Install alongside the toolkit or use standalone.
Looking for AGT-native integration? If you're using AGT's
ToolCallInterceptor,AuditBackend, orPolicyProviderInterfaceextension points, seearia-agentkit— which builds on this package and provides contract-tested adapters for the full AGT surface.
Links
- PyPI
- OpenID AuthZEN Specification
- Microsoft Agent Governance Toolkit
- EmpowerNow ARIA
aria-agentkit— AGT-native ARIA integration
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file authzen_policy_backend-0.1.2.tar.gz.
File metadata
- Download URL: authzen_policy_backend-0.1.2.tar.gz
- Upload date:
- Size: 21.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
faadf04b90dd06814f93d76379e42b45b02b2c993c591ec6da15814056acf6a9
|
|
| MD5 |
346443abaf68d04deb65c6db6cb3d8e1
|
|
| BLAKE2b-256 |
33edbbff228dbc25f5b6254f389236d69ae1728d88704ad0756f90a18a1413a0
|
File details
Details for the file authzen_policy_backend-0.1.2-py3-none-any.whl.
File metadata
- Download URL: authzen_policy_backend-0.1.2-py3-none-any.whl
- Upload date:
- Size: 16.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7650d20071d300486180b23643b256ada970cc9de6a07354a5011b51d1252f3f
|
|
| MD5 |
b463b01c1cde289fa50ac7f1f4c8685c
|
|
| BLAKE2b-256 |
5a741f1e9de690d95d99f5e68198ae3d95d54460445dc0ee3e7d001600d1d8cd
|