Saturday, September 19, 2026

Building Secure Azure AI Foundry Agents with Managed Identity

 

The credential problem nobody wants to own

Every team that connects an Azure AI Foundry agent to Microsoft Graph, SharePoint, Outlook, or a custom API eventually hits the same question: where do the credentials live?

The usual answers are client secrets, certificates, or a service account password tucked into a config file. All three work. All three also mean somebody now owns a rotation schedule, a secret store, and a risk register entry.

Managed Identity removes the question entirely. Azure gets the token; your agent never sees a secret.

This post walks through configuring an Azure AI Foundry agent to call Microsoft Graph using Managed Identity, including the permission model, the scoping controls, and the three errors you will almost certainly hit on the way.

Why Managed Identity wins

Managed Identity lets an Azure resource request Entra ID tokens on its own behalf. Nothing is stored, nothing expires on your watch.

What you get:

  • No secrets in application code or configuration
  • Token acquisition and renewal handled by the platform
  • A smaller attack surface and a cleaner compliance story
  • Native support for least-privilege access
  • First-class integration across Azure services

What you give up: the illusion that permissions come for free. More on that below.

The request path

Azure AI Foundry Agent
        │
        ▼
  Managed Identity
        │
        ▼
  Microsoft Entra ID
        │
        ▼
   Access Token
        │
        ▼
 Microsoft Graph API
        │
        ▼
Exchange Online / Teams / Users / Files

Step 1: Create a user-assigned managed identity

In the Azure Portal, go to Managed Identities → Create and supply a name, subscription, resource group, and region.

mrclmedpggblweuaip-mi

Once it exists, record three values. You will need all of them later:

  • Client ID
  • Object ID
  • Resource ID

User-assigned identities are the right default for enterprise work. They survive resource deletion, can be shared across services, and give you a stable object to audit.

Step 2: Assign Microsoft Graph permissions

This is the step most people skip, and it is the reason most first attempts fail.

A managed identity is an identity, not an authorization. Creating one grants access to exactly nothing. Microsoft Graph application permissions have to be assigned to it separately, as app role assignments on the Graph service principal.

PermissionPurpose
User.Read.AllSearch and read directory users
Calendars.ReadRead mailbox calendars
Mail.ReadRead mailbox messages
OnlineMeetings.Read.AllRead Teams meeting details
OnlineMeetingTranscript.Read.AllRead meeting transcripts

Then grant admin consent. Without it, every call returns:

Authorization_RequestDenied

Assign only what the agent actually needs. An agent that reads calendars has no business holding Mail.Read.

Step 3: Scope mailbox access (optional but recommended)

Application permissions on Graph are tenant-wide by default. Mail.Read means every mailbox in the organization.

For most enterprises that is far too broad, particularly during a pilot. Application Access Policies in Exchange Online restrict a given application to a specific mail-enabled security group.

A typical pilot limits Calendars.Read and Mail.Read to a small group of approved test users. Any mailbox outside that group returns:

json
{
  "error": {
    "code": "ErrorAccessDenied"
  }
}

Worth noting for troubleshooting: this is a different failure from a missing permission, and it looks different in the response. More on that in the error section.

Step 4: Create the Foundry agent

In Azure AI Foundry, open your project and go to Agents → Create Agent.

Configure the model (GPT-5.6 or whatever your organization has approved), the instructions, the tools, and any knowledge sources.

The instructions matter more than they look. Tell the agent to call tools rather than answer from its own knowledge:

You are an enterprise assistant.

Use the available tools to retrieve user, calendar, email and meeting
information whenever it is required. Always call the appropriate tool
rather than generating the information yourself.

Step 5: Add an OpenAPI tool

Go to Agent → Tools → Add Tool → OpenAPI and set the authentication:

Authentication Method : Managed Identity
Audience              : https://graph.microsoft.com

The audience is what tells Foundry which resource to request a token for. Get it wrong and you will get a 401 that looks like a permissions problem but is not.

Step 6: Start with a diagnostic schema

Resist the urge to paste in your full business schema on the first pass. Register one endpoint, confirm the pipe works end to end, then build on it.

A good first probe:

http
GET /users/{userEmail}/calendar

A successful call confirms three things at once: the managed identity acquired a token, Graph accepted it, and Calendars.Read is present and consented.

Two more worth running:

http
GET /users?$top=1

Validates User.Read.All.

http
GET /users/{userEmail}/messages?$top=1

Validates Mail.Read.

Run each from the Foundry playground and inspect Traces → Tool Execution afterwards. The trace shows the resolved URL, the audience, and the status code, which is where the actual diagnosis happens.

Three errors and what they actually mean

Authorization_RequestDenied (403)

The Graph application permission is missing, or admin consent was never granted.

Check the app role assignment on the managed identity, then check consent. These are two separate things and the second is easy to forget.

ErrorAccessDenied (403)

The permission exists, but the mailbox is outside the Application Access Policy scope.

This is the friendlier failure. Authentication worked and the permission is in place; the policy simply blocked this particular mailbox. Verify the mailbox is in the allowed group.

401 Unauthorized

Authentication itself failed. Usually one of:

  • The managed identity is not assigned to the Foundry resource
  • The audience URL is wrong
  • Token acquisition failed

Nothing about Graph permissions will fix a 401. Work backwards from the identity assignment.

The distinction between the two 403s is the single most useful thing to internalize here. One means "you were never allowed to ask." The other means "you may ask, but not about this mailbox."

Practices worth adopting

Prefer user-assigned identities for anything that will outlive a single resource or be shared across services.

Grant the minimum. Every Graph application permission is tenant-wide until you scope it.

Scope mailboxes with Application Access Policies, especially during pilots. Tenant-wide Mail.Read in a test environment is a finding waiting to happen.

Validate with diagnostic tools before writing business logic. A one-endpoint probe tells you whether the authentication chain works. A full schema tells you nothing until it does.

Document the permission-to-API mapping. When an auditor asks why this identity holds Mail.Read, you want a table, not a recollection.

Avoid client secrets wherever managed identity is supported.

Closing

Managed Identity is the right default for Foundry agents that talk to Microsoft Graph and other enterprise services. It removes secrets from the equation while leaving authentication and authorization where they belong, in Entra ID.

Pairing Foundry agents, managed identity, scoped Graph permissions, and Application Access Policies gives you agents that are useful without being over-privileged, and a governance story you can actually defend.

The setup takes an afternoon. The alternative takes a rotation schedule.

Monday, March 16, 2026

🚀 Building a Copilot‑based Meeting Scheduler (POC) using Microsoft Graph & Power Automate

 A practical, step‑by‑step guide for the Microsoft community


📌 Why this article?

Many teams are exploring Copilot Studio to build conversational experiences like:

“Can you help me find a good time for a meeting with my team?”

Behind the scenes, this requires:

  • Checking user availability
  • Respecting working hours
  • Suggesting realistic time slots

This is where Microsoft Graph shines — especially the findMeetingTimes API.

However, when people try this for the first time, they often hit challenges:

  • Premium license errors
  • Graph connection confusion
  • Copilot + Power Automate integration doubts

This article walks through a clean Proof‑of‑Concept (POC) approach, keeping things simple, understandable, and production‑ready later.


🧠 What we are building (POC scope)

✅ Copilot asks for meeting details
✅ Power Automate calls Microsoft Graph
✅ Graph suggests best available time slots
✅ Copilot responds with suggestions

🚫 No auto‑booking (yet)
🚫 No heavy governance (POC only)


🏗️ High‑level Architecture (POC)

User
 ↓
Copilot Studio Agent
 ↓
Power Automate Flow (POC)
 ↓
HTTP with Microsoft Entra ID
 ↓
Microsoft Graph – findMeetingTimes
 ↓
Suggested time slots
 ↓
Copilot responds to user

📎 Screenshot idea:

Diagram slide or whiteboard view of Copilot → Flow → Graph


🧩 Key Components Explained (in simple terms)

1️⃣ Copilot Studio

This is the conversation layer.
It collects:

  • Attendees
  • Meeting duration
  • Preferred date/time range

Copilot does not talk to Graph directly — it calls Power Automate.

📎 Screenshot: Copilot topic with trigger phrases and variables


2️⃣ Power Automate (Heart of the POC)

Power Automate acts as the orchestrator:

  • Receives input from Copilot
  • Calls Microsoft Graph
  • Formats the response back to Copilot

👉 For POC, the Power Automate Premium Trial is sufficient.

📎 Screenshot: Cloud flow triggered by Copilot


3️⃣ Microsoft Graph – findMeetingTimes

This API:

  • Looks at calendars
  • Considers working hours
  • Suggests realistic meeting slots

This avoids brute‑force checking and handles all the logic for you.


🔐 POC Licensing – Keep It Simple

For POC:

  • ✅ Start Power Automate Premium trial
  • ✅ Use your own user account
  • ✅ No service account needed yet

⚠️ Microsoft Graph in Power Automate is a Premium connector — this is expected and by design.

📎 Screenshot: Power Automate “Try premium” banner


🔗 Configuring Microsoft Graph Connection (POC)

Recommended connector

HTTP with Microsoft Entra ID

Why?

  • Simple
  • Supported
  • No custom connector maintenance

Connection setup

FieldValue
Base Resource URLhttps://graph.microsoft.com
Entra ID Resource URIhttps://graph.microsoft.com
AuthenticationUser sign‑in (POC)

📎 Screenshot: Creating HTTP with Entra ID connection



Suggestions

  1. Pick top 3 slots
  2. Convert to friendly text:
    • “Tuesday 11:00–11:30”
    • “Wednesday 3:00–3:30”

Copilot then replies conversationally:

“I found a few good options for everyone. Would you like to go with Tuesday at 11 AM?”


✅ Why this POC approach works well

✔ Minimal setup
✔ Matches real‑world behaviour
✔ No reinventing scheduling logic
✔ Easy upgrade path to PROD


🔜 How this POC evolves into PROD (Later)

POCProduction
User accountService account
Premium trialPer‑Flow license
Suggest onlyAuto‑book meetings
Light governanceFull security & auditing

Graph payloads stay the same
Copilot logic stays the same

Only ownership & licensing change.


❗ Common Pitfalls (and how to avoid them)

  • ❌ Trying to avoid Premium connectors → Not supported
  • ❌ Direct Graph calls from Copilot → Not possible
  • ❌ Using shared mailbox → Unsupported
  • ✅ Always go through Power Automate

📝 Final Thoughts

If you’re exploring Copilot Studio + scheduling scenarios, start small:

  • Prove value with findMeetingTimes
  • Keep the conversation human
  • Let Microsoft Graph do the heavy lifting

Once stakeholders see the value, moving to a production‑grade model is straightforward.


🙋‍♂️ I’d love community feedback!

If you’ve tried similar Copilot scheduling ideas or have tips, please comment and share your experience.
Happy to iterate and learn together 🚀

Building Secure Azure AI Foundry Agents with Managed Identity

  The credential problem nobody wants to own Every team that connects an Azure AI Foundry agent to Microsoft Graph, SharePoint, Outlook, or...