ADR-002: Agent User Over OBO for Device-Local Agents¶
Status: Accepted Date: 2026-04-06 Supersedes: ADR-001
Context¶
ADR-001 chose OBO (On-Behalf-Of) token exchange for device-local agent identity. This required:
- A human device-code flow to get an initial user token
- Caching the human's refresh token in the OS keychain
- MSAL runtime dependency for token acquisition
- A custom access_as_user scope on the Blueprint for audience matching
This worked but had fundamental problems: 1. Device-code flow requires a human — can't run headless, in CI, or on VMs without interaction 2. Refresh tokens expire and need management — complex keychain lifecycle 3. OBO is designed for "act on behalf of a user" — the agent IS its own entity, not acting on behalf of anyone
Meanwhile, Microsoft shipped Agent Users (public preview) — purpose-built Entra user accounts for agents that authenticate autonomously via the three-hop flow.
Decision¶
Replace the OBO chain with Agent User authentication:
The Agent User is a real Entra user object (microsoft.graph.agentUser) that:
- Gets tokens with idtyp=user (accepted by all user-context APIs)
- Can have a mailbox, Teams presence, OneDrive, org chart entry
- Authenticates exclusively through its parent Agent Identity (no passwords/MFA)
- Can be assigned M365 licenses
- Is governed by Conditional Access like any user
Consequences¶
Positive¶
- No human in the loop — fully autonomous authentication
- No device-code flow — works headless, in CI, on VMs
- No MSAL runtime dependency — raw httpx calls to the token endpoint
- No refresh token management — three-hop flow acquires fresh tokens each time
- Agent has its own Teams identity — messages come FROM the agent
- Cleaner separation: agent IS a digital worker, not impersonating a human
Negative¶
- Requires an M365 license per Agent User (~$8-36/month)
- Agent User is a preview feature (may change)
- Three-hop flow is more complex to debug than a single OBO call
- Blueprint needs
AgentIdUser.ReadWrite.IdentityParentedBypermission
Neutral¶
- Provisioner app pattern unchanged (still needed for setup)
- Audit attribution still works (agent identity in sign-in logs)
- Cross-platform credential storage still needed (for Blueprint secret in dev)