Build1 publisher3 min readPublished
Three permission problems wearing one service principal: why published agents return 403
A Foundry governance walkthrough splits agent permissions into on-behalf-of reads, unattended agent identity, and human approval. Collapsing them into one credential is a publish-time failure.
The Engineer · Build desk
Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

What happened
- An article published on dev.to ("Microsoft Foundry Agent Permission Governance: OBO, RBAC, and Approval Boundaries") turns a previously mapped Foundry identity model into a permission ledger, a publish-time migration plan, and a set of negative tests.
- The article uses one scenario to answer three questions: when an agent should use On-Behalf-Of (OBO) versus Agent Identity; why an agent can work in development and suddenly return a 403 after publication; and if RBAC is already in place, why high-risk tools still need approval.
- In the scenario, a salesperson asks the agent to help prepare for tomorrow's meeting with a customer, and the agent reads the email, calendar events, and documents that this user can access.
- In the same scenario, an enterprise scheduler starts a background job every night; through an MCP tool that supports Agent Identity, the agent creates a team-level customer summary and writes it to a designated Azure Storage container.
- In the third flow of the scenario, after the user confirms, the agent sends the meeting summary to attendees or updates a CRM record.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
A walkthrough published on dev.to takes Microsoft Foundry's agent identity model and converts it into a permission ledger, a publish-time migration plan, and a set of negative tests [1]. It is worth reading because of how it decomposes the problem: it asks when an agent should use On-Behalf-Of versus Agent Identity, why an agent can work in development and then return a 403 after publication, and why high-risk tools still need approval when RBAC is already configured [2].
The scenario is a sales team with three jobs for one agent. A salesperson asks it to prepare for tomorrow's meeting, and it reads the mail, calendar, and documents that this user can already access [3]. A nightly enterprise scheduler runs a background job that builds a team-level customer summary through an MCP tool and writes it to a designated Azure Storage container [4]. And after the user confirms, the agent sends the summary to attendees or updates a CRM record [5]. The author's point is that a single shared service principal would make all three flows work while erasing the boundaries between them [6].
The read path runs the user's token into the Foundry Agent Service, which mints an OBO token carrying the agent plus delegated user permissions [7]. This is not a copy of the user's rights: effective access stays bounded by the delegated scopes the app requested, user or admin consent, Conditional Access, and downstream authorization [8]. It also has a hard prerequisite. The caller must invoke the Agent API with the user's Microsoft Entra token, and an API key does not carry the delegated user context that an OBO-authenticated tool needs [9]. That is where the 403 lives. Nothing about the agent changed at publication; the shape of the caller did.
The nightly job cannot use that path at all, because there is no signed-in user [10]. It should run under its own Agent Identity with only the permissions the task requires [11], assuming the tool in front of the resource actually supports Agent Identity authentication [12]. So the interactive flow needs a user token and the unattended flow has none by construction, which means no single credential can legitimately serve both [1]. For a Prompt Agent the chain is Project Managed Identity to blueprint to Agent Identity token, then an exchange for a target-audience token [13]. The detail teams get wrong: per the Foundry Agent Identity documentation, the RBAC role on the target resource belongs on the Agent Identity, not on the Project Managed Identity used to authenticate the blueprint [14]. The example assigns Storage Blob Data Contributor to the agentIdentityId at the storage account scope [15]. If a freshly created Agent Identity will not resolve through --assignee because of Microsoft Graph propagation latency, the workaround is --assignee-object-id with --assignee-principal-type ServicePrincipal [16], which is worth knowing before it appears as a flaky pipeline step.
The third flow is the one RBAC does not answer. It is gated on user confirmation before anything leaves the building [5], which is why the ledger the author proposes carries six fields per action: principal, resource, action, scope, approval, and audit [17]. He insists the table exists before tools are configured, not after deployment, and that a team unable to fill in any one field has not yet defined an enforceable boundary [18].
Two things to check against your own build. First, whether every tool you plan to use supports the authentication method your architecture diagram assumes, since some support only a key, OAuth passthrough, or Project Managed Identity, and those bring sharing, rotation, revocation, and audit consequences that belong in the same ledger [19]. Second, whether your published trigger passes an Entra token or a key, because that answers the 403 before you file the bug.