The short version

  • One identity per agent, with a named owner, and certificates or managed identities instead of client secrets.
  • Delegated access when a person is in the loop; scoped application access when not.
  • Separate reading from acting, and put consequential actions behind an approval.
  • Treat everything the agent reads as untrusted input.
  • Log it, review it and keep an off switch.

Give every agent its own identity

Each agent gets its own app registration, or a managed identity if it runs in Azure, named after its job and with a named owner. Never borrow a person's account or a shared admin. Use certificates or managed identities rather than client secrets. Separate identities make every action attributable in the sign-in and audit logs, and let you switch off one agent without touching the others.

Choose delegated or application access deliberately

With delegated permissions, the agent acts as the signed-in user and can never exceed what that person can already do. With application permissions, it acts as itself across the whole organisation, with no user in the picture. Use delegated access whenever a person is in the loop. Keep application permissions for unattended work, and then narrow them.

Scope application permissions down

The permissions agents most often ask for are tenant-wide: Mail.ReadWrite for every mailbox, Files.ReadWrite.All for every file. Microsoft 365 has narrower options:

Often requestedUsually enough
Mail.ReadWrite across all mailboxesRBAC for Applications in Exchange Online, scoped to the mailboxes the agent serves
Files.ReadWrite.All or Sites.ReadWrite.AllSites.Selected, granting access to named SharePoint sites only
Chat.ReadWrite.AllResource-specific consent, limited to the chats and teams where the app is installed
Directory.ReadWrite.AllRead-only directory permissions, or none at all

Separate reading from acting

An agent that summarises email doesn't need permission to send it. If it drafts replies, it saves them as drafts for a person to send. Actions with consequences, such as sending outside the organisation, deleting data, changing permissions or making payments, go through an approval step the model cannot skip, enforced in code rather than in the prompt.

Treat everything the agent reads as untrusted

An email or document can contain instructions aimed at the agent: forward this thread, share that folder. This is prompt injection, and no instruction to the model reliably prevents it. The system around the model decides what is allowed: an allow-list of tools, validated parameters, fixed destinations and rate limits. Content from outside the organisation should never be able to trigger an action with side effects on its own.

Constrain where it signs in from

Conditional Access for workload identities can restrict an agent's service principal to known locations and block it when its risk rises. It needs Microsoft Entra Workload ID Premium. Without it, at least alert on service principal sign-ins from unexpected places.

Log it, review it and keep an off switch

  • Keep service principal sign-in logs and audit logs long enough to investigate an incident.
  • Alert when an agent is granted new permissions or credentials.
  • Review each agent's access every quarter, against its written job.
  • Document the off switch: disabling the service principal and removing its credentials stops new access immediately.

What we would do differently

Write the agent's job description before its permission list. Once the task is written down in two or three sentences, the permissions it needs are usually obvious, and the ones it doesn't need stand out.

Planning an agent that works inside Microsoft 365?

Talk to an engineer