If you are writing solutions that target Microsoft 365 services, you need to plan for permissions that your application will have to these resources.
It doesn't really matter if you are using Azure Services with Managed Identity, or a custom application with Service Principal. You have to set API permissions.
Architecture design
Let's imagine a "daemon" application (a software that runs in the background without user interaction) that needs to synchronize information between "Events" SharePoint Online list and an Exchange Online mailbox belonging to a group responsible for organizing these events. Invitations are sent to members of the group and replies need to be recorder in the list.
This means that the application needs to Read
and Write
to both: the SharePoint list and the Exchange calendar:
The business logic is implemented using Azure Function, with System-Managed Identity.
Some tests are performed using Postman, with a Service Principal.
API Permissions
I'm a staunch believer in a minimum-required permissions and would never implement an application that has indiscriminate access to all resources using Graph API (unless specifically required, that is).
SharePoint offers Sites.Selected
Application API permissions that together with Grant-PnPAzureADAppSitePermission
allow granting Read/Write
or FullControl
(with Set-PnPAzureADAppSitePermission
) permissions to the application identity.
But what about the mailboxes? The API permissions for Calendars grant access to all the mailboxes. That's a bit of overreach, innit?
Luckily there's a way to set granular access rights on the Exchange Online mailboxes as well!
There are two ways to do it:
- RBAC: Role Based Access Control for Applications in Exchange Online (Preview)
- Access Policy for Applications in Exchange Online: Limiting application permissions to specific Exchange Online mailboxes - Microsoft Graph
However, "App Access Policies will soon be replaced by Role Based Access Control for Applications." New-ApplicationAccessPolicy (ExchangePowerShell)
Setting RBAC
The procedure requires Exchange Online PowerShell
Let's use the Service Principal created for Postman.
In order to retrieve the information required for setting RBAC, you need to find out the Object and Application IDs belonging to the Enterprise Application and not the App Registration. Click on the App name under "Managed application in local directory"
You will be redirected to "Enterprise Application" page displaying the IDs you need to use:
Exchange Online Service Principal
Next, we need to create a Service Principal. Why?
In Exchange Online, service principals are references to the service principals in Azure AD. To assign Exchange Online role-based access control (RBAC) roles to service principals in Azure AD, you use the service principal references in Exchange Online.
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName
New-ServicePrincipal `
-AppId f3776ca2-2d7c-48f8-9e3c-7xxxxxxxxxxx `
-ObjectId b7cb2398-1e91-4a8b-95b8-xxxxxxxxxxxxx `
-DisplayName "Postman"
Exchange Online Management Scope
The Role Based Access Control for Applications in Exchange Online proposes two resource scopes for defining who has the RBAC:
- Management Scopes and
- Administrative Units
You have to go with Management Scopes to use the Managed Identity/Service Principals. Administrative units don't allow these.
New-ManagementScope `
-Name "My Scope" `
-RecipientRestrictionFilter "Alias -eq 'mailboxname' "
Exchange Online Management Role Assignment
And now we can grant the Service Principal the RBAC to the mailbox:
New-ManagementRoleAssignment `
-App "f3776ca2-2d7c-48f8-9e3c-7xxxxxxxxxxx" `
-Role "Application Calendars.ReadWrite" `
-CustomResourceScope "My Scope"
Did it work?
Test-ServicePrincipalAuthorization `
-Identity "f3776ca2-2d7c-48f8-9e3c-7xxxxxxxxxxx" `
-Resource mailboxname@tenantname.onmicrosoft.com
Did you know? You don't have to build the Graph API requests in Postman yourself. You can fork the Microsoft Graph collection and focus on the fun stuff.
Use Postman with the Microsoft Graph API
Limitations
- Applications can't become member of a Role Group.
- Application roles can only be assigned to Service Principals.
- Application roles can't be copied or derived.
- Exclusive management scopes don't restrict app access.
- Changes to app permissions are subject to cache maintenance that varies** between 30 minutes and 2 hours **depending on the app's recent usage. When testing configurations, the test command bypasses this cache. An app with no inbound calls to APIs will have its cache reset in 30 minutes, whereas an actively used app will keep its cache alive for up to 2 hours.
Full script
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName
$scopeName=""
$mailboxName=""
$tenantName=""
$appName=""
$appId=""
$objId=""
New-ServicePrincipal -AppId $appId -ObjectId $objId -DisplayName $appName
New-ManagementScope -Name $scopeName -RecipientRestrictionFilter "Alias -eq $mailboxName "
New-ManagementRoleAssignment -App $appId -Role "Application Calendars.ReadWrite" -CustomResourceScope $scopeName
Test-ServicePrincipalAuthorization -Identity $appId -Resource "$mailboxName@$tenantName.onmicrosoft.com"
Top comments (0)