DEV Community

Anton Staykov
Anton Staykov

Posted on

A transformational AI agent does not start with the permissions it needs

Most teams are still building AI agents the way they built automation in 2019: create an identity, shovel a pile of permissions onto it, pray the list is not too dangerous, and call that least privilege. That model was weak for static applications. For AI agents, it is worse.

An agent is not a static script. Its value comes from encountering new situations, discovering new APIs, and taking on work that was not fully known at deployment time. Pre-authorizing that kind of system is like issuing a master key because you do not know which doors the employee will need next month. Convenient, yes. Serious architecture, no.

The more useful pattern is the opposite: start the agent with effectively zero useful permissions for the task in front of it, let it discover what permission is actually missing when it hits a boundary, and force any expansion of access through a governed path such as access packages for agent identities. That is the pattern I wanted to understand better, so I built a practical sample around it.

The sample is astaykov/n8n-aca, a one-command starter for n8n on Azure Container Apps with Entra Agent ID. From Azure Cloud Shell, azd up provisions the Azure infrastructure, creates the Entra objects, installs the custom Entra Agent ID node for n8n, wires the credentials, imports the workflows, and activates the triggers. It is the fastest way I know to get from "I want to test agentic identity patterns" to a running system without spending the afternoon on scaffolding.

That convenience is not the interesting part, though. The interesting part is what the sample made easy to test: an autonomous agent on Microsoft Entra Agent ID that authenticates with its own identity, uses application permissions when it needs Microsoft Graph, and expands its access only through ID Governance when a real task justifies it.

The sample is the on-ramp, not the point

The repo gives a practical "one-click" starting point, even if the literal mechanism is a single command rather than a portal button. It deploys n8n on Azure Container Apps, provisions the surrounding Azure services, and creates the Entra building blocks you need: an agent identity blueprint and agent identity, plus the n8n credentials and workflows that let you immediately test autonomous and assistive patterns.

That matters because identity architects do not need another abstract reference architecture. They need something they can stand up, inspect, and break. The sample gives you that. But the design pattern it enables is the real story.

Microsoft Entra Agent ID exists precisely because traditional, deterministic application identities are the wrong abstraction for agents that evolve in production. Microsoft says that plainly: classic application identities were designed for static workloads and do not bring the governance model agents need, while agent identities and blueprints add lifecycle, sponsorship, and policy structure that maps to how agents actually operate. Once you accept that framing, the next question becomes obvious: if the identity model is dynamic, why are we still designing permissions as if they were static?

The right starting state is deliberate under-permissioning

When people hear "start with zero permissions," they often imagine an unusable toy. That is not what I mean.

I mean zero useful permissions for the specific task the agent has not encountered yet.

The authorization model for Entra Agent ID already points in that direction. Agents can use delegated permissions or application permissions, but high-risk permissions are blocked, lower-privilege access is preferred, and administrators are expected to grant access in a scoped way. Governance for agent identities goes one step further by describing access packages as the structure through which agents can receive OAuth application permissions, group memberships, and Entra roles in a time-bound, auditable way.

That combination changes the design target. The goal is no longer "figure out every permission the agent might need before go-live." The goal is "build an agent that can recognize a missing permission, identify the governed package that provides it, and request it through policy."

That is the shift. It is subtle, but it is the whole game.

Where the pattern actually lives in n8n

At a glance, the workflow looks almost too simple to carry this much identity behavior: webhook in, token acquisition, AI agent, webhook out. That is exactly why the image earns its place here. The interesting part is not the number of nodes. It is the control logic concentrated inside the agent and its tools.

The n8n workflow is visually simple by design: webhook, Entra token acquisition, AI agent, and response, with Azure OpenAI, memory, Microsoft Learn MCP, and Microsoft Graph attached as the agent's runtime dependencies.

The workflow is intentionally compact. The design pattern does not live in a sprawling orchestration graph; it lives in the policy encoded into the AI Agent node and the constraints encoded into the Microsoft Graph tool.

In my workflow, the pattern is not hidden in a policy engine or spread across ten helper scripts. It lives in two very concrete places:

  1. The system prompt for the AI Agent node.
  2. The custom configuration of the HTTP Request tool that calls Microsoft Graph.

That is worth emphasizing because too many "agentic architecture" discussions still pretend the prompt is fluff. It is not. In a tool-using agent, the system prompt is operational policy.

The n8n AI Agent node is a tools-based agent. It receives the user request, chooses tools, reasons about tool responses, and keeps going until it can answer or it hits a policy boundary. In this workflow, the agent is told something very specific:

You are an AI Agent with your own Microsoft Entra identity.
You authenticate as yourself using Microsoft Graph application permissions.
When any API call returns 401 or 403, do NOT give up.
Identify the exact permission, search access packages, inspect each package,
and request the matching package if self-request is allowed.
Enter fullscreen mode Exit fullscreen mode

That instruction is doing real architectural work. It teaches the agent to treat 401 and 403 as a discovery loop, not as a dead end.

It also teaches the agent to stay honest about what kind of access it has. The prompt explicitly says it only works with application permissions for Microsoft Graph. That matters because Entra Agent ID distinguishes autonomous agents from assistive agents, and the permission model is different depending on whether the agent is acting as itself or on behalf of a user. For this workflow, the autonomous case is the point.

The Microsoft Learn MCP server is the underrated component

The agent has two tools in the workflow: a Microsoft Graph HTTP tool and a Microsoft Learn MCP client pointing at https://learn.microsoft.com/api/mcp.

That second tool is the underrated component.

The Microsoft Learn MCP Server is public, free, and does not require authentication. More importantly, it gives the agent runtime access to official documentation and code examples through MCP instead of forcing you to hardcode every Microsoft Graph rule into the prompt. That is what turns the workflow from "an agent with a bag of fixed API calls" into "an agent that can learn how to call Graph correctly when it needs to."

In practice, that means the agent can look up an endpoint, confirm which permission is required, and use the error it just received to tighten the search. That is the missing bridge between language-model flexibility and enterprise identity controls. Without it, the agent is guessing. With it, the agent has a documentation brain.

The HTTP tool matters just as much as the prompt

The n8n HTTP Request node is versatile enough to be dangerous, which is exactly why the custom tool configuration matters.

In this workflow, the HTTP tool is constrained to https://graph.microsoft.com, prefers /v1.0/ over /beta/, uses a predefined bearer credential, and is instructed to research the endpoint before writes. More importantly, it is configured to return the full response and never error. That is not a cosmetic choice. It means the agent gets the status code and body back even when Graph refuses the call, so it can reason over the authorization failure instead of having the workflow short-circuit.

That one setting turns a generic REST tool into a permission-discovery instrument.

The tool instructions also tell the agent to confirm state-changing operations before execution, except for one case: creating an access package assignment request. That exception is deliberate. If the whole point is to let the agent acquire governed access in context, then the request path itself needs to be part of the autonomous loop.

How the governed escalation loop works

The loop is simple enough to explain, which is usually a sign you are finally dealing with the right abstraction.

First, the agent attempts the Graph operation the user asked for.

If Microsoft Graph returns 401 or 403, the agent uses the error plus the Learn MCP server to identify the exact missing permission. The prompt forces it to write down the permission explicitly and to treat it as an application permission in this workflow.

Next, it enumerates the available access packages with GET /identityGovernance/entitlementManagement/accessPackages. Then it inspects the package contents through resource role scopes, looking for the role that maps to the missing permission. This is the key architectural move: the agent is not inventing new access. It is discovering which pre-governed package the identity team already made available.

Once it finds the matching package, it reads the assignment policies to determine whether self-request is allowed. If it is, the agent creates a POST /identityGovernance/entitlementManagement/assignmentRequests call for itself. If self-request is not allowed, it gives the user the package name, what it grants, and the My Access link so the user, their manager, or the sponsor can request it on the agent's behalf.

That is the pattern in one sentence: the agent can discover and request governed access, but it cannot bypass governance.

This is why access packages for agent identities matter so much. Microsoft explicitly supports three pathways: the agent can request access programmatically, the sponsor can request it on behalf of the agent, or an administrator can assign it directly. The workflow leans into those pathways instead of trying to outsmart them.

Why identity architects should care

This is not just a clever n8n trick. It is a better control model.

When an identity team pre-grants broad application permissions to an agent, they are making an up-front guess about future behavior. Those guesses age badly. They are rarely revisited, almost never shrunk, and eventually become the authorization equivalent of legacy firewall rules.

Access packages change the conversation. They let the identity team define bundles of allowed access, the approval and request policies, the expiration model, and the human accountability path. The agent still moves fast, but the boundary conditions are owned by governance, not improvised in code.

That is why I think this pattern matters: it decouples permission discovery from permission approval.

The agent is free to discover what it needs. The organization is still in control of whether that need maps to an approved package, whether self-request is allowed, who must approve it, and when the access expires. That is a much more adult architecture than stuffing Directory.Read.All into an app registration because the pilot customer wants the demo today.

The uncomfortable but necessary conclusion

The industry still talks about agent permissions as if the main design question were "what should this agent have?" That is already the wrong question.

The better question is: how should this agent acquire access when reality teaches us that the original permission set was incomplete?

If your answer is "we will update the app registration manually," you do not have an agentic permission model. You have an operations backlog.

If your answer is "the agent starts narrow, learns what permission is missing from the task and the docs, maps that need to a governed access package, and either requests it or hands the human the approval path," then you are finally designing for the world these systems actually live in.

That is what this sample helped me understand. n8n on Azure Container Apps with Entra Agent ID is a useful accelerator. The deeper lesson is the design pattern itself: agents should not begin life over-permissioned. They should begin life constrained, then earn their scope through policy, context, and governance.

That shift is the part identity architects should care about.

References

Top comments (0)