Delegated Authentication
When an agent needs to act on behalf of a user (customer support, scheduled jobs, microservice chains), MACAW provides cryptographically secure delegation tokens with full audit trails.
The Delegation Model
Delegator (User)
│
│ grants delegation token
▼
Delegate (Agent) ────────────► Resource
│ │
└── Audit trail shows both ────┘
user AND agent identityBoth the original user (delegator) and the agent (delegate) are recorded in the audit trail, providing complete accountability for delegated actions.
Key Concepts
Scoped Delegation
Delegation tokens specify exactly what operations are allowed, with time limits and purpose tracking. Delegates can only access what they're explicitly granted.
Multi-Hop Chains
Identity flows through service chains. Each hop can only restrict scope, never expand. The full delegation chain is recorded in the audit trail.
Time-Bounded
All delegation tokens have expiry times. An approval from yesterday doesn't authorize today's action unless explicitly allowed.
Revocable
Delegations can be revoked at any time by the delegator or an administrator. Revocation is immediate and propagates through the chain.
Multi-Hop Agent Chain
Alice → Orchestrator → Tool A → Tool B
┌─────────────┐ alice_jwt ┌─────────────────┐ alice_context ┌─────────────────┐
│ Alice │────────────▶│ Orchestrator │────────────────▶│ Tool Agent A │
│ │ │ │ │ │
│ "Process │ │ security_context│ │ Uses Alice's │
│ my data" │ │ = { │ │ permissions │
│ │ │ company: "FC", │ │ │
│ │ │ bu: "Analytics"│ alice_context │ ┌─────────────┐ │
│ │ │ user: "alice" │────────────────▶│ │Tool Agent B │ │
│ │ │ } │ │ │ │ │
│ │ │ │ │ │Uses Alice's │ │
│ │ │ │ │ │permissions │ │
└─────────────┘ └─────────────────┘ │ └─────────────┘ │
└─────────────────┘
Result: Alice's identity and policies flow through entire chainAt each hop, the security context is preserved and can only be further restricted. Tool Agent B operates under Alice's permissions, not its own elevated permissions.
Creating a Delegation Token
from macaw_client import MACAWClient
client = MACAWClient(app_name="scheduler")
# Create a delegation token for a scheduled job
delegation = client.create_delegation(
delegator_jwt=user_jwt, # Alice's JWT
delegate_id="scheduler-job-123",
scope={
"resources": ["tool:database/query"],
"constraints": {
"parameters": {
"tool:database/query": {
"tables": ["reports"]
}
}
}
},
purpose="Daily report generation",
expires_in=3600, # 1 hour
max_uses=10 # Optional: limit total uses
)
# Use the delegation token
response = client.invoke_tool(
tool_name="database",
operation="query",
params={"table": "reports", "limit": 100},
delegation_token=delegation.token
)
# Audit shows:
# - Original user: alice@company.com
# - Delegate: scheduler-job-123
# - Purpose: Daily report generationScope Restrictions
Delegation scopes follow intersection semantics—the delegate gets the intersection of the delegator's permissions and the granted scope:
Alice's Policy: resources: [tool:database/*, tool:api/*] max_tokens: 2000 Delegation Scope: resources: [tool:database/query] max_tokens: 500 Delegate's Effective Permissions: resources: [tool:database/query] ← Intersection max_tokens: 500 ← More restrictive
Security Property
A delegator cannot grant more permissions than they have. The delegation scope can only restrict, never expand, the delegator's permissions.
Common Use Cases
Scheduled Jobs
A user authorizes a scheduled job to run reports on their behalf while they're away.
delegation = client.create_delegation(
delegator_jwt=user_jwt,
delegate_id="daily-report-job",
scope={"resources": ["tool:database/query"]},
purpose="Daily sales report",
expires_in=86400 # 24 hours
)Customer Support
Support agent accesses a customer's data to troubleshoot an issue, with full audit.
delegation = client.create_delegation(
delegator_jwt=customer_jwt, # Customer grants
delegate_id="support-agent-alice",
scope={"resources": ["data:customer/view"]},
purpose="Ticket #12345 troubleshooting",
expires_in=3600,
max_uses=5
)Microservice Chain
A user's identity flows through a chain of microservices processing their request.
# Service A receives user request
delegation_a = client.create_delegation(
delegator_jwt=user_jwt,
delegate_id="service-b",
scope={"resources": ["api:process/*"]},
purpose="Request processing",
expires_in=60
)
# Service B uses delegation_a to call Service C
# (Can only further restrict, never expand scope)