Sitemap

Your Copilot Studio agent is acting as someone, do you know who?

7 min readMar 30, 2026

--

If you don’t know who that is, you might already have a security risk⚠️

Disclaimer the scope of this blog post are Microsoft Copilot Studio agents, not AI foundry or security copilot

Press enter or click to view image in full size
Agent Authentication

There are four* different authentication options for Microsoft Copilot Studio agents.

*5 if you count No authentication, more details in my previous blog

1️⃣ Copilot Studio → End user credentials authenticates [OBO]

  • Authentication → Authenticate with Microsoft
  • Credentials to use → End user credentials

The user authenticates [once] and the agent transparently exchanges the token to access resource on behalf of (OBO) the user (in the context of the user’s permissions).

Press enter or click to view image in full size
Agent | End user credentials

There are no access permissions defined or sign-in logs available for the agent because everything happens in the context of the signed in user.

Sign-in logs for the user are available in Entra

The risk of this type of agent authentication is low

2️⃣ Copilot Studio → Maker user credentials

  • Authentication → Authenticate with Microsoft
  • Credentials to use → Maker-provided credentials ⚠️

The agent authenticates once at design time using the maker’s identity, and then reuses that connection at runtime for every user.

Press enter or click to view image in full size
Maker-provided credentials

There are no access permissions defined or sign-in logs available because everything happens in the context of the maker credentials.

Sign-in logs for the user are available

The risk of this type of agent authentication is high⚠️ due to silent authentication (stored credentials) and the risk of data oversharing.

3️⃣ Entra → App Registration with Delegation Permissions

  • Authentication → Authenticate manually
  • Microsoft Entra ID V2 with <AuthMethod>

The agent uses an Entra app registration, but still acts on behalf of the signed-in user (delegated), constrained by both the user’s rights (e.g. Mail.Read, User.Read) and the app’s granted scopes (e.g. Mail.Read, Calendar.Read), the effective permissions are Mail.Read;the agent can read the user’s mailbox.

HTTP Request

To use an App registration, an HTTP Request in a Topic is required (e.g. Show Mail), see trigger flow below

Topic Authenticate HTTP Request Message <Response>

Press enter or click to view image in full size
Headers and body | Authorizaton key VALUE

Use "Bearer “ & System.User.AccessTokenvalue as formula in the HTTP Request → Headers and body for the Authorizaton key value.

To view the permissions use the Message node (after the Authenticate node) with User.AccessToken.Ingest the Token in a JSON Web Token reader.

],
"app_displayname": " OBO-Agent-Delegated-Credentials",
"appid": "3ba86861-89ef-46a2-84ee-00c44b6bde50",
"appidacr": "1",
"deviceid": "123b5260-09a7-4035-b6c1-8823ae261b83",
"family_name": "van der Woude",
"given_name": "Derk",
"idtyp": "user",
"ipaddr": "216.243.17.16",
"name": "Derk van der Woude | Blue16",
"oid": "e837c09a-3bbe-46ab-8259-43635660b9a8",
"platf": "3",
"puid": "10037FFE957CFDBB",
"rh": "1.AUgAoLbSghVxwUSnh04BOSuFKgMAAAAAAAAAwAAAAAAAAAALAYNIAA.",
"scp": "Mail.Read openid profile User.Read email",
"sid": "0099fdf9-f80b-ed6b-ce4e-2f8845822723",
"signin_state": [
"kmsi"
],

Use the exact same values in the Scopes section of the Authentication → Authenticate manually settings (via Microsoft Entra ID V2 with <auth_method>)

Authentication Scopes

Sign-in logs can be found in Entra → Agent ID → All agent identities → <Agent> → Sign-in logs → Service principal sign-ins

Press enter or click to view image in full size
Agent ID with Service Principal | SIgn-in log

The risk of this type of agent authentication is low

4️⃣ Entra → App Registration with Application Permissions ⚠️

  • Authentication → Authenticate manually
  • Microsoft Entra ID V2 with <AuthMethod>

The agent uses an Entra App Registration and authenticates as the application itself, not on behalf of a user. There is no user context (no OBO), and access is determined by the app’s granted application permissions (e.g. Mail.Read, Mail.Read.All, User.Read.All).
The effective permissions are those assigned to the app, meaning the agent can access data across users or the entire tenant (Admin consent required), depending on the granted scopes.

HTTP Request

To use an app registration with application permissions, an HTTP Request in a Topic is required (e.g. Show Mail), since built-in connectors typically rely on delegated flows.

Topic → Authenticate (client credentials) via HTTP Request [Post] → HTTP Request [Get] → Message <Response>

Press enter or click to view image in full size
Authenticate (client credentials) via HTTP Request [Post]

Sign-in logs can be found in Entra → Agent ID → All agent identities → <Agent> → Sign-in logs → Service principal sign-ins

The risk of this type of agent authentication is very high⚠️ due to Admin consent (tenant), high privileged access (HPA) and the risk of data oversharing.

🔍Advanced Hunting → AIAgentsInfo

Via the AIAgentsInfo table in Advanced Hunting we can detect agent authentication methods. Deployment of this feature is described in my previous blog.

Although Microsoft Foundry and Copilot Studio are supported in the Assets → AI agents section. Only Copilot Studio are supported in Advanced Hunting (for now).

Key Fields for Authentication Detection

The two most important fields are:

  • UserAuthenticationType — the agent-level authentication method (e.g. Integrated, None)
  • AuthenticationTrigger — when authentication is triggered (e.g. As Needed)
Press enter or click to view image in full size
Advanced Hunting → AIAgentsInfo table

1️⃣ Discover agents with No authentication (high risk ⚠️)

Authentication | No Authentication

The KQL script discovers all agents without authentication.

AIAgentsInfo
| summarize arg_max(Timestamp, *) by AIAgentId
| where AgentStatus == "Published"
| where UserAuthenticationType == "None"
| project AgentCreationTime, AIAgentId, AIAgentName, AgentStatus, CreatorAccountUpn, OwnerAccountUpns

2️⃣ Discover agents with Maker credentials (high risk ⚠️)

Press enter or click to view image in full size
Maker credentials

This KQL script discovers all agents with Maker credentials configured in the Tools / MCP Server connection settings.

let base = AIAgentsInfo
| summarize arg_max(Timestamp, *) by AIAgentId
| where AgentStatus == "Published";
let directActions = base
| mv-expand detail = AgentToolsDetails
| where detail.action.connectionProperties.mode == "Maker"
| extend ActionType = "FromTools", Action = detail.action
| project-reorder AgentCreationTime, AIAgentId, AIAgentName, UserAuthenticationType ,CreatorAccountUpn;
let topicActions = base
| mv-expand topic = AgentTopicsDetails
| extend topicActionsArray = topic.beginDialog.actions
| mv-expand Action = topicActionsArray
| where Action.connectionProperties.mode == "Maker"
| extend ActionType = "FromTopic"
| project-reorder AgentCreationTime, AIAgentId, AIAgentName, AgentStatus, CreatorAccountUpn, OwnerAccountUpns, Action;
directActions
| union topicActions
| sort by AIAgentId, Timestamp desc

Keep in mind that two of more misconfigurations compound the risk level, e.g. No Authentication and Maker credentials

3️⃣Discover agents using HTTP Request actions to Microsoft Graph (potential app-permission agents ⚠️)

Press enter or click to view image in full size
App registration authentication

This KQL script finds agents with entra app registration authentication.

Delegated permissions, low risk, advise to verify the scope (API permissions)

⚠️ Application permissions, high risk, the agent is acting as itself across the whole tenant

AIAgentsInfo
| summarize arg_max(Timestamp, *) by AIAgentId
| where AgentStatus != "Deleted"
| mvexpand Topic = AgentTopicsDetails
| where Topic has "HttpRequestAction"
| extend TopicActions = Topic.beginDialog.actions
| mvexpand action = TopicActions
| where action['$kind'] == "HttpRequestAction"
| extend Url = tostring(action.url.literalValue)
| extend ParsedUrl = parse_url(Url)
| extend Host = tostring(ParsedUrl["Host"])
| where Host has_any("graph.microsoft.com", "management.azure.com")
| project-reorder AgentCreationTime, AIAgentId, AIAgentName, ParsedUrl, Url, Host, AgentStatus, CreatorAccountUpn, OwnerAccountUpns
Press enter or click to view image in full size
Example

Conditional Access for Agents

The authentication flow for modern Agent ID authentication (not OBO) is twofold: an Exchange Token(T1) issued via the Agent Identity Blueprint, and an Access Token(T2) issued via the Agent Identity to access resources.

Press enter or click to view image in full size
agent identity authentication flow

Conditional Access for Agents is triggered in step 4 for Agent Identities and/or Agent Users, not for Agent Blueprint (they only serve as grouping in the Conditional Access policy).

At the time of writing (this might change in the future), Copilot Studio agents rely on user (OBO) or workload (service principal) identities as described above, not modern Agent ID authentication. This means Conditional Access for Agents (and ID Protection for Agents) do not apply, as authentication happens in the context of a user or service principal, not the agent identity itself.

ID Protection for Workload identities is a secure alternative for the agents authenticating via an app registration.

The modern agent ID authentication flow is used by Security Copilot and AI Foundry (OAuth 2.0) agents.

Comparison Table

Press enter or click to view image in full size
Comparison Table

As always, I hope you took something useful away from my learning journey 🙏

--

--