M365 Development

Restricting Azure Function access to a single Shared Mailbox using Role Based Access Control (RBAC) for Applications in Exchange Online

The objective of this post is to detail the steps required to configure Exchange Online RBAC for Applications so that an Azure Function using a system‑assigned managed identity can perform Calendars.ReadWrite operations only on one specific shared mailbox. All other mailbox scopes must return AccessDenied.

Content


Prerequisites

Azure

  • Azure Function with system‑assigned managed identity
    • Application ID: 458f1d57-9413-4824-b9d7-abed2934c819
    • Object ID: 74fac675-00ea-4f7f-a3e6-88ce3e4478c2

Exchange Online / Microsoft 365

  • Shared mailbox: rbac_shared@tenant.onmicrosoft.com
  • Other mailbox used for denial example: other_mailbox@tenant.onmicrosoft.com

Tools

  • ExchangeOnlineManagement v3+ PowerShell module

Connect to Exchange Online PowerShell

To configure Application RBAC, connect with appropriate admin privileges:

PowerShell
Connect-ExchangeOnline

This session is required to create the management scope, register the service principal, and assign the built‑in role.


Enable Organization Customization

Application RBAC requires that your tenant has organization customization enabled.

PowerShell
Enable-OrganizationCustomization

This is a one‑time operation per tenant.


Create a Recipient‑Restricted Management Scope

Select RecipientRestrictionFilter to ensure the role assignment applies only to the shared mailbox.

Create the scope

PowerShell
New-ManagementScope `
  -Name "RBAC_SingleMailboxScope" `
  -RecipientRestrictionFilter "PrimarySmtpAddress -eq 'rbac_shared@tenat.onmicrosoft.com'"

Why this matters

This restricts the managed identity’s RBAC role so it only applies to this one mailbox. Even though the Graph permission is broad (Calendars.ReadWrite application permission), RBAC restricts its effective reach.


Register the Service Principal in Exchange Online

This step brings the Entra ID service principal into Exchange Online’s RBAC system.

PowerShell
New-ServicePrincipal `
  -AppId '458f1d57-9413-4824-b9d7-abed2934c819' `
  -SerivceId '74fac675-00ea-4f7f-a3e6-88ce3e4478c2' `
  -DisplayName 'AzureFunctionMI'

The SerivceId for a system‑assigned identity is the Object ID of the managed identity, AppId is the Application ID (managed identity Application ID can be found in Entra ID.


Role Assignment

Assign a built-in role (Application Calendars.ReadWrite) to the service principal.

You can find other supported roles here: Supported Application Roles

PowerShell
New-ManagementRoleAssignment `
  -App "458f1d57-9413-4824-b9d7-abed2934c819" `
  -Role "Application Calendars.ReadWrite" `
  -CustomResourceScope "RBAC_SingleMailboxScope"

This assignment grants permission only to the mailbox permitted by the custom scope created earlier.


Test RBAC Authorization

Before testing you requests on the Azure function, you can first directly test the serivce principal access using Test-ServicePrincipalAuthorization.

Allowed mailbox test

PowerShell
Test-ServicePrincipalAuthorization `
  -Identity "458f1d57-9413-4824-b9d7-abed2934c819" `
  -Resource "rbac_shared@tenant.onmicrosoft.com"

You should get the following as a result:

PowerShell
RoleName             : Application Calendars.ReadWrite
GrantedPermissions   : Calendars.ReadWrite
AllowedResourceScope : RBAC_SingleMailboxScope
ScopeType            : CustomRecipientScope
InScope              : True
Identity             : 74fac675-00ea-4f7f-a3e6-88ce3e4478c2
IsValid              : True
ObjectState          : New

Validate with Microsoft Graph API

Your Azure function will call the endpoint:

C#
/users/{id}/events

Using the shared mailbox’s UPN.

Allowed request:

Request

C#
GET https://graph.microsoft.com/v1.0/users/rbac_shared@tenant.onmicrosoft.com/events

Example JSON response body (success)

JSON
[
  {
    "Id": "AAMkAGE2...",
    "Subject": "This is a test meeting",
    "Start": "2026-02-05T14:00:00.0000000",
    "StartTz": "Europe/Paris",
    "End": "2026-02-05T14:30:00.0000000",
    "EndTz": "Europe/Paris",
    "Location": "Microsoft Teams Meeting",
    "Organizer": "rbac_shared@tenant.onmicrosoft.com",
    "IsAllDay": false,
    "WebLink": "https://outlook.office365.com/owa/?itemid..."
  }
]

Denied request:

Request

C#
GET https://graph.microsoft.com/v1.0/users/other_mailbox@tenant.onmicrosoft.com/events

Example JSON response body (denied)

JSON
{
  "error": {
    "code": "ErrorAccessDenied",
    "message": "Access is denied. Check credentials and try again."
  }
}

This confirms the RBAC enforcement is working as expected:
Only the permitted shared mailbox is accessible.


Summary

Exchange Online RBAC allows you to restrict your Azure function’s Microsoft Graph API access to a single mailbox.


References

Leave a Reply