Application permissions to access mailboxes
Sometimes you work on an application that needs access all mailboxes in your organization on Exchange Online.
Apps that have been granted the following application permissions
- Calendars.Read - Allows the app to read events of all calendars without a signed-in user.
- Calendars.ReadBasic.All - Allows the app to read events of all calendars, except for properties such as body, attachments, and extensions, without a signed-in user.
- Calendars.ReadWrite - Allows the app to create, read, update, and delete events of all calendars without a signed-in user.
- Contacts.Read - Allows the app to read all contacts in all mailboxes without a signed-in user.
- Contacts.ReadWrite - Allows the app to create, read, update, and delete all contacts in all mailboxes without a signed-in user.
- Mail.Read - Allows the app to read mail in all mailboxes without a signed-in user.
- Mail.ReadBasic - Allows the app to read basic mail properties in all mailboxes without a signed-in user. Includes all properties except body, previewBody, attachments and any extended properties.
- Mail.ReadWrite - Allows the app to create, read, update, and delete mail in all mailboxes without a signed-in user. Does not include permission to send mail.
- Mail.Send - Allows the app to send mail as any user without a signed-in user.
- MailboxSettings.Read - Allows the app to read user's mailbox settings without a signed-in user. Does not include permission to send mail.
- MailboxSettings.ReadWrite - Allows the app to create, read, update, and delete user's mailbox settings without a signed-in user. Does not include permission to send mail.
can access all the mailboxes. If you want to limit app access to specific mailboxes, Exchange administrators have to configure Application Access Policy through Exchange Online tools.
You can't do the whole setup with one tool, but you need Microsoft Entra tool like the Graph API (create Entra app, grant application permissions) and Exchange Online tool (limit access to specific mailboxes).
Fortunately, the Graph API comes with a new set of endpoints for Exchange Online RBAC provider to make the process simpler.
Role-Based Access Control (RBAC)
Let's start with basic terms.
Role definition
A role definition (just called a role) is a collection of permissions. A role lists the actions that can be performed.
Security principal
A security principal is an object that represents a user, group, service principal, or managed identity that is requesting access to tenant resources. Role can be assigned to any of these security principals.
Scope
Scope is the set of resources that the access applies to. When you assign a role, you can further limit the actions allowed by defining a scope.
Role assignment
A role assignment is the process of attaching a role definition to a user, group, service principal, or managed identity at a particular scope for the purpose of granting access.
- Access is granted by creating a role assignment
- Access is revoked by removing a role assignment
Exchange Online RBAC provider
Exchange Online RBAC provider allows admins to grant permissions to an application that's independently accessing data in Exchange Online. This grant can be paired with a scope of access (resource scope) to specify which mailboxes an app can access. This feature extends the current RBAC model in Exchange Online and it replaces Application Access Policies.
The Graph API beta provides endpoints to list role definitions for Exchange Online RBAC provider and create, remove and list role assignments.
Application roles
Let's explore the roles that are allowed by Exchange Online RBAC provider for service principals. When using the Graph PowerShell SDK, use Get-MgBetaRoleManagementExchangeRoleDefinition
cmdlet.
Import-Module Microsoft.Graph.Beta.DeviceManagement.Enrollment
Connect-MgGraph -Scopes "RoleManagement.Read.Exchange"
Get-MgBetaRoleManagementExchangeRoleDefinition -Filter "allowedPrincipalTypes eq 'servicePrincipal'"
Name | Id | Description | Application permissions for Graph API |
---|---|---|---|
Application Mail.Read | 1f704712-7d46-481f-b2cd-dbcc978c4f2a | Allows the app to read email in all mailboxes without a signed-in user | Mail.Read |
Application Mail.ReadBasic | 3eca55c8-0e73-4c12-81bf-526549f2e5a3 | Allows the app to read email except the body, previewBody, attachments, and any extended properties in all mailboxes without a signed-in user | Mail.ReadBasic |
Application Mail.ReadWrite | 82fd214e-61ca-4dc7-98f6-090700bdb205 | Allows the app to create, read, update, and delete email in all mailboxes without a signed-in user. Does not include permission to send mail | Mail.ReadWrite |
Application Mail.Send | 8679f4ff-c91d-40d0-809c-c86d114821a5 | Allows the app to send mail as any user without a signed-in user | Mail.Send |
Application MailboxSettings.Read | c40299e0-2107-455f-85dd-6e8862c3a0cc | Allows the app to read user's mailbox settings in all mailboxes without a signed-in user | MailboxSettings.Read |
Application MailboxSettings.ReadWrite | 459cb245-07c5-44f1-8133-3da40b4b6197 | Allows the app to create, read, update, and delete user's mailbox settings in all mailboxes without a signed-in user | MailboxSettings.ReadWrite |
Application Calendars.Read | a3123d4e-4256-4ad0-bef0-205a00807fae | Allows the app to read events of all calendars without a signed-in user | Calendars.Read |
Application Calendars.ReadWrite | b92761c0-5311-4908-92ca-2c1f8c71aa1c | Allows the app to create, read, update, and delete events of all calendars without a signed-in user | Calendars.ReadWrite |
Application Contacts.Read | 9b87c446-d3c1-4146-9d39-45ae63b4eeb7 | Allows the app to read all contacts in all mailboxes without a signed-in user | Contacts.Read |
Application Contacts.ReadWrite | 265cabb3-13d9-4e05-b2cd-460cfa7ad3cc | Allows the app to create, read, update, and delete all contacts in all mailboxes without a signed-in user | Contacts.ReadWrite |
Application Mail Full Access | b49ae303-7a8f-4ba1-aa37-27b40461aabb | Allows the app to create, read, update, and delete email in all mailboxes as well as send mail as any user without a signed-in user | Mail.Send Mail.ReadWrite |
Application Exchange Full Access | 48d6a78c-0681-4d73-acec-9f9ffad56ddb | Without a signed-in user: Allows the app to create, read, update, and delete email in all mailboxes as well as send mail as any user. Allows the app to create, read, update, and delete user's mailbox settings in all mailboxes. Allows the app to create, read, update, and delete events of all calendars. Allows the app to create, read, update, and delete all contacts in all mailboxes | Contacts.ReadWrite Calendars.ReadWrite MailboxSettings.ReadWrite Mail.Send Mail.ReadWrite |
Each role definition includes a list of Graph API role permissions.
Security principal
Only allowed security principal for Exchange Online provider is a service principal (it means also managed identity)
Scope
For Exchange Online provider, the scope for the role assignment can be the whole tenant, a specific user, a specific group (direct members), or an administrative unit.
Check the table below for correct formats
Scope | Format |
---|---|
Tenant-wide | / |
User | /Users/{userId} |
Administrative unit | /AdministrativeUnits/{administrativeUnitId} |
Group | /Groups/{groupId} |
Examples
Example 1
You would like to create an app that can read calendars of users which are members of a administrative unit called Developers.
The steps are:
1. Create an application
Use New-MgBetaApplication
cmdlet.
Import-Module Microsoft.Graph.Beta.Applications
$params = @{
displayName = "CalendarsReader"
}
$app = New-MgBetaApplication -BodyParameter $params
$appObjectId = $app.Id
$appId = $app.AppId
2. Create a service principal
By using New-MgBetaServicePrincipal
. It requires application id (appId).
$params = @{
appId = "$appId"
}
$servicePrincipal = New-MgBetaServicePrincipal -BodyParameter $params
$principalId = $servicePrincipal.Id
3. Add client secret
By using Add-MgBetaApplicationPassword
. It requires application object id.
$params = @{
passwordCredential = @{
displayName = "Default secret"
}
}
$appSecret = Add-MgBetaApplicationPassword -ApplicationId $appObjectId -BodyParameter $params
$clientSecret = $appSecret.SecretText
4. Create role assignment
The last step is to create a new role assignment by using New-MgBetaRoleManagementExchangeRoleAssignment
. For the assignment, we need service principal id, role definition id and administrative unit id.
Import-Module Microsoft.Graph.Beta.DeviceManagement.Enrollment
$unit = Get-MgBetaAdministrativeUnit -Filter "displayName eq 'Developers'"
$unitId = $unit.Id
$role = Get-MgBetaRoleManagementExchangeRoleDefinition -Filter "displayName eq 'Application Calendars.Read'"
$roleId = $role.Id
$params = @{
principalId = "/ServicePrincipals/${principalId}"
roleDefinitionId = $roleId
directoryScopeId = "/AdministrativeUnits/${unitId}"
appScopeId = $null
}
New-MgBetaRoleManagementExchangeRoleAssignment -BodyParameter $params
The whole PowerShell script
Import-Module Microsoft.Graph.Beta.Applications
Import-Module Microsoft.Graph.Beta.DeviceManagement.Enrollment
Connect-MgGraph -Scopes "RoleManagement.ReadWrite.Exchange", "Application.ReadWrite.All"
# create app
$params = @{
displayName = "CalendarsReader"
}
$app = New-MgBetaApplication -BodyParameter $params
$appObjectId = $app.Id
$appId = $app.AppId
# create service principal
$params = @{
appId = "$appId"
}
$servicePrincipal = New-MgBetaServicePrincipal -BodyParameter $params
$principalId = $servicePrincipal.Id
# wait for a while until service principal is fully provisioned
Start-Sleep 20
# add client secret
$params = @{
passwordCredential = @{
displayName = "Default secret"
}
}
$appSecret = Add-MgBetaApplicationPassword -ApplicationId $appObjectId -BodyParameter $params
$clientSecret = $appSecret.SecretText
# create role assignment
$unit = Get-MgBetaAdministrativeUnit -Filter "displayName eq 'Developers'"
$unitId = $unit.Id
$role = Get-MgBetaRoleManagementExchangeRoleDefinition -Filter "displayName eq 'Application Calendars.Read'"
$roleId = $role.Id
$params = @{
principalId = "/ServicePrincipals/${principalId}"
roleDefinitionId = $roleId
directoryScopeId = "/AdministrativeUnits/${unitId}"
appScopeId = $null
}
New-MgBetaRoleManagementExchangeRoleAssignment -BodyParameter $params
Test
Use Get-MgBetaUserEvent
cmdlet to confirm that the app can access calendars only for users from Developers administrative unit. Read events for one user which is a member of the administrative unit and for user which is not a member.
Import-Module Microsoft.Graph.Beta.Calendar
$tenantId = "<tenant_id>"
$clientSecret = "<client_secret>"
$appId = "<app_id>"
$clientSecretCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $appId, (ConvertTo-SecureString -String $clientSecret -AsPlainText -Force)
Connect-MgGraph -ClientSecretCredential $clientSecretCredential -TenantId $tenantId
Write-Host "Reading events for Nestor Wilke"
$events = Get-MgBetaUserEvent -UserId '74db2ae6-6aa4-4160-8c2a-c93d4f1cfafa'
Write-Host "Number of events: " $events.length
Write-Host "Reading events for Adele Vence"
Get-MgBetaUserEvent -UserId '61b0c52f-a902-4769-9a09-c6628335b00a'
Disconnect-MgGraph
As you can see from the result, the attempt to read Adele Vence calendar failed with error code ErrorAccessDenied, because Adele is not a member of the administrative unit and the role Calendars.Read is restricted only to the admin unit.
Example 2
You need an app that will synchronize contacts between users from Sales department. The app will be assigned the Application Contacts.ReadWrite role and restricted to the Sales group.
$group = Get-MgBetaGroup -Filter "displayName eq 'Sales'"
$groupId = $group.Id
$role = Get-MgBetaRoleManagementExchangeRoleDefinition -Filter "displayName eq 'Application Contacts.ReadWrite'"
$roleId = $role.Id
$params = @{
principalId = "/ServicePrincipals/${principalId}"
roleDefinitionId = $roleId
directoryScopeId = "/Groups/${groupId}"
appScopeId = $null
}
New-MgBetaRoleManagementExchangeRoleAssignment -BodyParameter $params
Example 3
Some company employees are on vacation without access to their emails. You need an app that will check emails from a specific customers. The app will be assigned the Application Mail.ReadBasic role and restricted to a specific user.
$userId = '{user_id}'
$role = Get-MgBetaRoleManagementExchangeRoleDefinition -Filter "displayName eq 'Application Mail.ReadBasic'"
$roleId = $role.Id
$params = @{
principalId = "/ServicePrincipals/${principalId}"
roleDefinitionId = "$roleId
directoryScopeId = "/Users/${userId}"
appScopeId = $null
}
New-MgBetaRoleManagementExchangeRoleAssignment -BodyParameter $params
Example 4
Your employee is missing, you need an app with the full access to employee's mailbox. The app will be assigned the Application Exchange Full Access role and restricted to a specific user.
$userId = '{user_id}'
$role = Get-MgBetaRoleManagementExchangeRoleDefinition -Filter "displayName eq 'Application Exchange Full Access'"
$roleId = $role.Id
$params = @{
principalId = "/ServicePrincipals/${principalId}"
roleDefinitionId = "$roleId
directoryScopeId = "/Users/${userId}"
appScopeId = $null
}
New-MgBetaRoleManagementExchangeRoleAssignment -BodyParameter $params
Example 5
You need an app that can change mailbox settings like default time zone, date and time format, track working hours of all users in your tenant. The app will be assigned the Application MailboxSettings.ReadWrite role without any scope restriction.
$role = Get-MgBetaRoleManagementExchangeRoleDefinition -Filter "displayName eq 'Application MailboxSettings.ReadWrite'"
$roleId = $role.Id
$params = @{
principalId = "/ServicePrincipals/${principalId}"
roleDefinitionId = "$roleId"
directoryScopeId = "/"
appScopeId = $null
}
New-MgBetaRoleManagementExchangeRoleAssignment -BodyParameter $params
Conclusion
Exchange Online RBAC provider offers an alternative way to configure application permissions to access users mailboxes, and can be used side-by-side with granting application permissions and configuring application access policies.
https://learn.microsoft.com/graph/api/rbacapplication-post-roleassignments?view=graph-rest-beta