A declarative agent in Microsoft 365 Copilot becomes a data path out of the tenant the moment someone gives it an action that calls an external API or a remote MCP server. The agent's instructions and knowledge sources run inside Microsoft 365, but each action carries its own credentials, scopes and endpoint, and the model decides when to call it based on the prompt, the instructions and whatever the last action returned. This guide covers the security of declarative agent actions only: API plugin and MCP action authentication, the auth configs held in the Microsoft Enterprise token store, OAuth and Entra single sign-on set-up, how far an action's data can reach, and how to monitor it. It is written for Microsoft 365 administrators, identity engineers and developers who build or approve agents. For Agent Store approval, admin roles and tenant-wide Copilot settings, see the Microsoft 365 Copilot Security Deep Dive; for the low-code maker platform, see the Securing Microsoft Copilot Studio Agents Guide.
This is an independent guide from NHI Mgmt Group, based on Microsoft's public documentation as of November 2026. It is not sponsored or reviewed by Microsoft. Product features change, so confirm settings against Microsoft's current documentation.
Key takeaways
- Every action is a non-human identity. An OAuth client registration, an Entra SSO registration or an API key registration in the Teams developer portal is a credential with an owner, a scope and a lifetime, and it belongs in your NHI inventory.
- Secrets stay out of the manifest by design. The plugin manifest holds only a
reference_idpointing at an auth config in the Microsoft Enterprise token store; keep it that way and treat any key or secret found in a repository as compromised. - Omitted scope means everything. Leaving out both
items_by_urlanditems_by_sharepoint_ids, orconnectionsorsitesin the declarative agent manifest gives the agent all SharePoint and OneDrive sources, all Copilot connectors or all web sites the user can reach. - Action output is untrusted input. Microsoft states that data returned by custom actions can influence the agent, so an action that returns emails or tickets can carry indirect prompt injection into the next tool call.
- Consequential calls need a human. Declare
ResourceStateUpdateandDataExporthonestly insecurity_info, keep confirmation cards on, and do not mark write operations as non-consequential.
How declarative agent actions work
A declarative agent is a manifest, not a hosted service. It defines instructions, knowledge capabilities and up to 10 entries in its actions array (declarative agent manifest schema; Microsoft lists 1.9 as the latest version as of November 2026). Each action points to a plugin manifest file, usually ai-plugin.json, which declares one or more runtimes. The plugin manifest schema 2.4 defines three runtime types:
- OpenApi: an API plugin described by an OpenAPI document. The
serversarray sets where calls go. - RemoteMCPServer: a remote MCP server. The manifest connects the agent to the server; it does not package or host it. Microsoft 365 Agents Toolkit (6.12.0 or later) configures dynamic tool discovery by default, so the tool list is resolved at runtime unless you pin a curated set.
- LocalPlugin: a local endpoint in a host application, restricted by
allowed_hosttodocument,mail,presentationorworkbook.
The run_for_functions property limits which functions a runtime serves; if it is omitted, every function the runtime describes is available. That default matters most for MCP, where a server operator can add tools after you approved the agent. See the AI Agent Tool and Plugin Security Guide for the general tool risk model.
At runtime Microsoft 365 Copilot fetches a token or key from the token store and attaches it to the outbound call. Microsoft's extensibility guidance is explicit that a plugin does not grant a user access to Microsoft 365 data they are not already authorised to see, but the external API or MCP server enforces its own permissions. The security of an action is therefore the security of the external service and the identity it trusts.
Choosing an authentication scheme
Microsoft documents four schemes. Support differs between API plugins and MCP plugins, so pick by runtime type first.
| Scheme | API plugins | MCP plugins | Manifest auth.type | Identity the external service sees | Use when |
|---|---|---|---|---|---|
| Microsoft Entra SSO | Supported | Supported | OAuthPluginVault | The signed-in user, delegated, via the token store client | The API is protected by Entra ID and should act as the user |
| OAuth 2.0 authorisation code (static registration) | Supported | Supported | OAuthPluginVault | The user, as authorised at a third-party identity provider | A SaaS API with its own OAuth server |
| OAuth dynamic client registration (DCR) | Not supported | Supported | Set by tooling | The user, via a client the MCP server registers at runtime | An MCP server that supports DCR and is not Entra protected |
| API key | Supported | Not supported for declarative agent actions | ApiKeyPluginVault | One shared key for every user | Read-only, low-sensitivity APIs with no user context |
| None (anonymous) | Supported | Offered in Agents Toolkit | None | Nobody | Public data only (GetPublicData) |
Decision guidance: prefer delegated schemes (Entra SSO or OAuth authorisation code) whenever the API returns data that differs per user, because the external service can then enforce that user's rights and its own logs show who acted. An API key collapses every user into one identity, so the API cannot tell an intern from a finance director and any user of the agent gets whatever the key can reach. Use keys only where that is genuinely acceptable, and never for an action that writes. For Entra-protected MCP servers, Microsoft notes DCR is not available, so register the client statically. See the MCP Authorisation Specification Guide for how DCR and protected resource metadata work in the protocol itself.
Configuring OAuth and Entra SSO connections safely
Auth configs are created by Microsoft 365 Agents Toolkit or manually in the Teams developer portal under Tools. Each creates a record in the token store and returns an ID that goes into the manifest as reference_id. The portal fields are where most of the security decisions live.
| Field (portal) | Secure setting | Why |
|---|---|---|
| Base URL | Exact API base matching an OpenAPI servers entry, or the MCP server spec url | The token store releases the credential only for calls to this base, so a broad or shared host widens where tokens can go |
| Restrict usage by org | My organization only, unless the plugin is genuinely cross-tenant | Any Microsoft 365 organization lets other tenants use the registration |
| Restrict usage by app | API plugins: bind to the published app ID once known. MCP plugins: Any Teams app | Microsoft warns that binding an MCP registration to one Teams app ID makes every tool call return 404 |
| Enable PKCE | Leave on (the default) | Turn it off only if the provider cannot support PKCE |
| Client secret | Avoid where possible: register a public client (single-page application platform) and rely on PKCE | Removes a long-lived secret to rotate and leak |
| Scope | Only the delegated scopes the functions need; add offline_access only when refresh is required | Refresh tokens extend the life of a granted session |
For OAuth, register https://teams.microsoft.com/api/platform/v1.0/oAuthRedirect as the redirect URI at the provider and nothing broader. For Entra SSO the set-up has more moving parts, and each one is an access decision:
- Register the API app in the Microsoft Entra admin center and note its client ID.
- Create the Microsoft Entra SSO client ID registration in the Teams developer portal with the base URL, org restriction and scopes. Save it to get the auth config ID and an Application ID URI.
- Add the Application ID URI to
identifierUrisin the app manifest (the admin center UI only shows the first URI, so use the manifest editor). - Add the redirect URI
https://teams.microsoft.com/api/platform/v1.0/oAuthConsentRedirecton the Web platform. - Pre-authorise the Microsoft Enterprise token store client ID
ab3be6b7-f5df-413d-ac2d-abf1e3fd9c0bunder Expose an API, for the specific scopes needed and no others. - Update token validation in the API: accept the new Application ID URI as an audience and, if you check the calling client, allow the token store client ID. If the API calls a downstream API through the on-behalf-of flow and needs consent, return 401 so the user is prompted.
Two operational details catch teams out. Provisioning does not verify consent, so an unconsented scope only fails later with "Need admin approval"; grant or deny admin consent deliberately before release rather than letting users request it ad hoc. And the Agents Toolkit oauth/register step never overwrites an existing record, so changed scopes or endpoints need oauth/update, and only the developer portal can delete a registration. Stale registrations accumulate unless someone owns them. See Consent Phishing and Illicit OAuth Grants Guide for consent governance and How to rotate Entra app secrets without downtime where a confidential client is unavoidable.
Controlling what an action can reach and do
Data reach has two halves: what Microsoft 365 data the agent can ground on and pass into an action, and what the action can read or change in the external system.
- Scope knowledge capabilities explicitly: in the declarative agent manifest, list SharePoint and OneDrive sources with
items_by_urloritems_by_sharepoint_ids, Copilot connectors withconnections, Teams sources withurls, meetings withitems_by_id, and web search with up to foursites. Microsoft's schema states that omitting these properties gives access to all sources of that type. KeepPeopleinclude_related_contentat its default of false unless the scenario needs related mail and chats. - Declare data handling truthfully: each function's
security_info.data_handlingtakesGetPublicData,GetPrivateData,DataTransform,DataExportorResourceStateUpdate. Microsoft states thatResourceStateUpdaterequires explicit user confirmation, and that a function withoutsecurity_infocannot interact with other plugins or capabilities of the agent. Review these values as part of approval: a function that sends Microsoft 365 content to the API isDataExport, whatever its name suggests. - Keep confirmations meaningful: the
confirmationobject can show an Adaptive Card with a title and body.isNonConsequentialset to true lets users choose "Always Allow"; it has no effect on non-GET operations, and for GET operations anx-oai-isConsequentialvalue in the OpenAPI document takes precedence. Write card text that names the target record and effect, not "Are you sure?". - Limit functions per runtime: use
run_for_functionsand, for MCP, pinned tools rather than dynamic discovery for production agents, so a new tool on the server is not callable until someone reviews it. See the MCP Server Trust Assessment before approving a third-party server. - Carry labels into responses:
response_semantics.properties.information_protection_labellets an API return a sensitivity indicator with each result, so users see classification on external data too. See the Microsoft Purview Information Protection Guide.
Indirect prompt injection: Microsoft's data, privacy and security guidance warns that if an action can return untrusted content such as emails or support tickets, crafted input could change the agent's behaviour or trigger actions, and recommends enabling only agents that use trusted knowledge and trusted REST APIs, with careful human intervention for sensitive operations. The practical rule is that an agent which reads untrusted content should not hold a write or export action in the same manifest. See MITRE ATT&CK T1698 Indirect Prompt Injection and the OWASP LLM Top 10 LLM06 Excessive Agency Guide.
Risk to control mapping for actions
| Risk | How it shows up | Control |
|---|---|---|
| Over-broad grounding | Agent summarises a confidential site into an external API call | Explicit knowledge scoping; DataExport declared and reviewed |
| Shared credential | API key gives every agent user the same rights | Delegated OAuth or Entra SSO; keys only for public read data |
| Cross-tenant use of a registration | Registration set to any organisation without need | Restrict usage by org to your tenant |
| Tool drift on MCP servers | New tool appears through dynamic discovery after approval | Pinned tools, run_for_functions, re-approval on change |
| Injection through action output (T1698) | Returned ticket text instructs the agent to call a write function | Separate read and write agents; confirmations; untrusted sources excluded |
| Token theft at the API (T1528) | Access tokens logged or replayed by the external service | Audience validation, short token lifetime at the provider, no tokens in logs |
| Orphaned registrations | Auth configs remain after an agent is retired | Owner per registration, quarterly review, delete in the portal |
Where identity fits
The agent itself acts with the signed-in user's identity, but each auth config is a separate machine credential: a client ID, possibly a client secret, refresh tokens held on behalf of users and, for API keys, a static secret. They are created in a developer portal, often by a developer rather than an identity team, and they outlive the project unless retired. Record each one with its owner, base URL, tenant restriction, scopes, secret type and expiry alongside your other app registrations. Users can sign out of an action from Chat settings > Agents in Microsoft 365 Copilot, which clears their stored OAuth token, but revocation for everyone has to happen at the identity provider. See the Agentic AI Identity Guide and How to detect new credentials added to an app registration.
Rolling out actions safely
- Inventory: list declarative agents that have actions, their plugin manifests, runtime types, base URLs and auth config IDs. Microsoft recommends recording each data flow's owner, source, destination, location, classification, retention and failure behaviour.
- Classify each function: set
data_handling, confirm read versus write, and decide whether the agent mixes untrusted inputs with consequential actions. Split agents where it does. - Fix authentication: move user-specific APIs from keys to delegated OAuth or Entra SSO; set org restriction to your tenant; keep PKCE on; remove client secrets where a public client works.
- Pin and scope: add knowledge scoping properties, pin MCP tools and set
run_for_functions. - Pilot: develop in a test tenant with My organization only registrations, sideload to a small group, and review audit records for every function call before wider release.
- Approve and publish: submit through the admin approval path described in the Microsoft 365 Copilot Security Deep Dive, attaching the data flow record.
- Roll back: block or remove the agent in the Microsoft 365 admin center Agents page, then revoke consent and delete or disable the auth config so tokens already held stop working. Rotate the API key or client secret if it may have been exposed.
Small versus large organisations: a small tenant can have one administrator approve each action against the checklist below and keep the inventory in a spreadsheet. Large tenants should require a named owner per auth config, route new registrations through change control, and run the review in their identity governance tool so registrations without an owner are flagged automatically.
Detection and measurement
Microsoft Purview Audit (Standard) records Copilot use in CopilotInteraction events with no extra set-up when auditing is on. Useful fields for actions:
| Field | What it tells you | Use |
|---|---|---|
AgentId, AgentName, AgentVersion | Which agent ran (for example CopilotStudio.Declarative.<GUID>) | Tie activity to the inventory; spot unknown agents |
AISystemPlugin (Name, ID, Version) | Plugins used in the interaction | Alert on an unapproved plugin or version change |
AccessedResources | Resources read or changed, with Action, SensitivityLabelId and XPIADetected | Flag labelled content in sessions that also called an export action; investigate cross-prompt injection detections |
Messages.JailbreakDetected | Jailbreak classifier hit on a prompt | Correlate with subsequent action calls |
Admin operations CreatePlugin, DeletePlugin | Plugin lifecycle changes | Change control evidence |
The external API or MCP server must log too: the user principal from the token, the function called, and the result. Without that, audit records show that an action ran but not what it did. See the Microsoft 365 Unified Audit Log Guide for Detection.
Metrics:
- Delegated auth share: percentage of production actions using Entra SSO or OAuth rather than API keys or none (target: all actions that return user-specific data).
- Owned registrations: percentage of auth configs with a named owner and review in the last 90 days.
- Scoped agents: percentage of agents whose knowledge capabilities all carry explicit scoping properties.
- Write functions with confirmation: percentage of
ResourceStateUpdateandDataExportfunctions with an Adaptive Card confirmation that names the effect. - XPIA detections per 1,000 action calls: trend, with each detection triaged.
Framework mapping
| Framework | Reference | How actions map |
|---|---|---|
| NIST CSF 2.0 | PR.AA-01, PR.AA-05 | Auth configs managed as identities; least-privilege scopes and knowledge scoping, reviewed |
| NIST CSF 2.0 | GV.SC-07, DE.CM-09 | Third-party API and MCP server risk assessed and monitored; agent activity monitored |
| NIST SP 800-53 Rev 5 | AC-6, AC-3, CM-7 | Least privilege, enforcement at the API, only needed functions enabled |
| NIST SP 800-53 Rev 5 | CA-3, SA-9, AU-6 | Documented information exchange with external services; audit review |
| ISO/IEC 27001:2022 Annex A | 5.15, 5.19, 8.15 | Access control, supplier relationships, logging |
| MITRE ATT&CK v20 | T1698, T1528 | Indirect prompt injection through action output; theft of application access tokens |
| OWASP LLM Top 10 2025 | LLM01, LLM06 | Prompt injection; excessive agency through over-permissioned actions |
Common failure patterns
- Unscoped knowledge plus an export action: the agent can ground on any site the user can open and send a summary to an external API. Scope sources and declare
DataExport. - API key on a per-user API: everyone using the agent gets the key's full rights and the API cannot attribute actions. Move to delegated OAuth.
- Registration open to any organisation: a test registration left on Any Microsoft 365 organization after go-live. Restrict to your tenant.
- Dynamic tool discovery in production: the MCP server adds a delete or send tool and the agent can call it the same day. Pin tools and re-approve on change. See the MCP Gateway and MCP Server Governance Guide.
- Write operations marked non-consequential: "Always Allow" removes the human from a state change. Keep write functions consequential.
- Retired agent, live credentials: the agent is removed from the store but the auth config, consent grant and refresh tokens remain. Retire all three together.
Practitioner checklist
- Inventory every declarative agent action with runtime type, base URL, auth config ID, owner and data flow record.
- Use Entra SSO or OAuth authorisation code for any API that returns user-specific data; reserve API keys for public read-only data.
- Set every registration to My organization only unless cross-tenant use is documented.
- Keep PKCE on and prefer public clients over client secrets.
- Grant admin consent deliberately before provisioning, for the minimum scopes.
- Add explicit scoping properties to every knowledge capability and keep
include_related_contentfalse by default. - Declare accurate
data_handlingvalues and keep confirmations onResourceStateUpdateandDataExportfunctions. - Pin MCP tools and set
run_for_functionsfor production agents. - Monitor
CopilotInteractionrecords forAISystemPlugin,AgentIdandXPIADetected, and log calls at the external service. - On retirement, block the agent, revoke consent and delete the auth config.
Standards and references
- Microsoft Learn: Configure authentication for API plugins and MCP plugins
- Microsoft Learn: OAuth 2.0 authentication for plugins
- Microsoft Learn: Microsoft Entra SSO for plugins
- Microsoft Learn: API plugin manifest schema 2.4
- Microsoft Learn: Declarative agent manifest schema
- Microsoft Learn: Data, privacy and security considerations for extending Microsoft 365 Copilot
- Microsoft Learn: Audit logs for Copilot and AI applications
- Microsoft Learn: Build plugins from an MCP server
Related NHI Mgmt Group resources: Microsoft 365 Copilot Security Deep Dive · Securing Microsoft Copilot Studio Agents Guide · Remote MCP Server Hardening Guide · AI Agent Tool and Plugin Security Guide