Six years ago I wrote a small sample to help me better understand how the On-Behalf-Of (OBO) flow actually works — a browser SPA calling a middle-tier Web API, which called Azure SQL on behalf of the signed-in user. Today it might be an assistive AI agent calling a MCP Server with the delegated constrains of the end-user. Same rules apply. This article explains why.
Three sentences that should survive beyond any particular technology:
If your system acts on behalf of a user, delegation rules apply.
If delegation rules apply, Conditional Access applies at token issuance for the downstream resource.
APIs, agents, and MCP servers don't change that — they just change the shape of the middle tier.
If an AI agent acts on behalf of a user, your existing Conditional Access policies that govern how users access corporate data already apply — automatically. You don't need to invent "agent-specific Conditional Access" for assistive agents. Assistive agents don't bypass Conditional Access. They inherit it.
If you understand OBO and Conditional Access from classic Web APIs, you already understand how Entra Agent ID behaves for assistive AI agents. Delegation semantics didn't change. Conditional Access behavior didn't change. Only the shape of the middle tier changed.
1. The Classic Delegated Access Pattern
The baseline architecture is the standard delegated access chain:
User
↓
SPA (interactive client)
↓ access token [aud = Web API]
Web API (confidential client)
↓ OBO token [aud = Resource]
Azure SQL | MCP Server
Two facts to hold firmly:
- The Web API never authenticates as itself to the downstream resource. It always acts on behalf of the signed-in user.
- The downstream resource — Azure SQL, Microsoft Graph, or an MCP server — sees a delegated token. It evaluates the user's identity and the delegated scopes. Conditional Access policies have already been enforced by Entra during token issuance.
2. The Web API has a real identity — and delegation is explicitly granted
This is the detail most diagrams omit, and it matters in production.
The Web API is not just "code that runs somewhere". In Microsoft Entra it is a registered application with its own identity. That identity authenticates to the token endpoint as a confidential client, using a client secret or certificate.
In a real OBO implementation, the Web API does two things simultaneously:
- Authenticates as itself — proving "I am the Web API" using its own credentials.
- Requests a delegated token for the downstream resource on behalf of the user, presenting the incoming user token as an assertion.
Critically, the capability to do OBO is not implicit. The Web API's identity must be explicitly granted the delegated permissions (scopes) for the downstream resource. The tenant administrator grants this; the Web API cannot do it on its own authority.
Practical framing: the Web API authenticates as itself, but it can only mint delegated tokens because the tenant has explicitly authorized it to act on the user's behalf for the specific downstream resource.
3. OBO in 90 Seconds
The flow has three steps:
- The user signs in to the client and the client receives an access token whose audience is the Web API. The client uses that access token to call the Web API.
- The Web API calls the token endpoint and exchanges that client token for a new one.
- The resulting token is minted for the downstream resource and carries the user's identity from step 1 and delegated scopes from step 2.
In protocol terms, the exchange looks like this:
POST /<tenant_id>/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion=<incoming_user_access_token>
&requested_token_use=on_behalf_of
&scope=https://database.windows.net/.default
&client_id=<api_client_id>
&client_secret=<api_client_secret>
Note both elements in the same request: client authentication (client_id + client_secret) and the user assertion (assertion). Both are required.
The invariant: OBO is strictly delegated. It uses delegated scopes, not application roles. Application permissions are not involved.
4. Conditional Access: who is targeted vs. who "feels" it
This is where real misunderstanding happens — and the confusion compounds when agents enter the picture.
Rule 1 — CA is assigned to the user and targets the resource.
A Conditional Access policy that requires MFA to access Azure SQL (or an MCP Server) is scoped to the user and the downstream resource. Evaluation happens when Microsoft Entra issues the delegated token for that resource — at the moment the OBO token is minted. Not when the user signs into the SPA. Not when the middle tier starts up.
Rule 2 — The middle tier is not a CA subject.
Even though the Web API has its own registered identity, it is not the subject of a CA policy intended to govern how users access corporate data. The CA policy constrains the user's access, not the middle-tier service identity. This remains true regardless of what the middle tier is: Web API, assistive AI Agent, MCP Server, or anything else.
Rule 3 — The middle tier still experiences CA outcomes.
When the Web API calls the token endpoint to acquire an OBO token, CA enforcement happens there. If CA requires step-up (like MFA), the token endpoint returns interaction_required with a claims challenge. The middle tier cannot satisfy this itself. It must surface this challenge back to the interactive client (the SPA in our case). The user performs the MFA, the client obtains a new token, and the middle tier retries the OBO exchange.
The one-liner: the middle tier is a CA messenger, not a CA subject.
5. Replacing the Web API with an (assistive) AI Agent (with an Agent Identity)
The transition to Entra Agent ID is explicit and mechanical:
| Role | Classic World | Agentic World |
|---|---|---|
| Middle Actor | Web API | AI Agent |
| Identity Type | app reg. | Agent Identity |
| Access Mode | Delegated (OBO) | Delegated (OBO) |
| CA Evaluation | On the resource | On the resource |
Nothing in the right column is new behavior. When using Entra Agent ID in delegated mode — the appropriate mode for an assistive agent acting on behalf of a signed-in user — three requirements apply:
- The Agent Identity must be granted the delegated permissions needed for the downstream resource.
- The Agent Identity acquires a delegated token representing the user, carrying their identity and scopes.
- The Agent Identity is constrained by Conditional Access policies that govern the user's access to that resource.
The core continuity: you replaced the middle-tier actor, not the trust boundary.
6. MCP Server as the Downstream Resource
MCP servers can feel "agent-native," which leads engineers to assume the security model has changed around them. It hasn't.
An MCP Server is an OAuth-protected resource — a server that accepts access tokens.
Do not pass tokens through. Equally valid for the AI agent acting on-behalf-of the user, but also for an MCP Server requesting authorizations to further resources on-behalf-of the user.
Beyond that, whether the downstream resource is Azure SQL, Microsoft Graph, or anything else, the CA and delegation rules are identical. From Microsoft Entra's perspective it is an OAuth-protected resource. Tokens are issued for it, delegated permissions are scoped to it, and Conditional Access policies target it.
7. What to Actually Configure
- Model your chain. Identify the downstream resource (REST API or MCP server) and the middle actor (Web API or agent identity in delegated mode).
- Make delegation explicit. Confirm the middle actor is granted the delegated permissions required for the downstream resource.
-
Treat CA challenges as a product requirement. Expect
interaction_requiredresponses and claims challenges during downstream token acquisition. In your agent's backend, implement a handler forMsalUiRequiredException(for example). Design the user interaction path to satisfy step-up — do not swallow these errors. - Never pass tokens through. Validate the incoming token for the agent audience, then acquire a fresh token for any downstream resource.


Top comments (0)