Notes from the field: Using app-only authentication with customized RBAC roles in Exchange Online
Published Dec 05 2022 07:33 AM 157K Views

Many Exchange Online customers are in the final phase of migrating to OAuth (or what we call Modern authentication) and finally disabling Basic authentication for their clients. The latest summary with migration resources is at Basic Authentication Deprecation in Exchange Online – September 2022 Update.

In this post, I focus on Exchange Online PowerShell as the client used for administration. In the past, it was used with Basic authentication as that was the only available authentication option. But that has changed, and the article Understanding the Different Versions of Exchange Online PowerShell Modules and Basic Auth tells you the whole story. What I would like to highlight is that the latest v3 module has been available for some months now and it replaces older Exchange Online PowerShell modules you might be using. v3 can be installed side-by-side with older versions to allow you to quickly fallback if something goes wrong. One nice feature of the v3 module is that it eliminates the "client machine WinRM Basic Authentication" dependency that is considered a security risk by some. Prior to the introduction of the v3 module, disabling Basic authentication for WinRM (About the Exchange Online PowerShell V2 module and V3 module) would break Exchange Online PowerShell functionality.

Using Modern authentication for interactive logons is easy; just install the Exchange Online PowerShell v3 Module and start your connection login through the Modern authentication dialog and you are done. So, the Azure AD sign-in logs won’t include interactive admin user authentication anymore.


If you still see those logins listed, the cause might be that in addition to the interactive logon, Exchange Online PowerShell is often used in automation scripts with service accounts. These service accounts might still be using Basic authentication to connect to Exchange Online as interactive logon doesn't work in that scenario.

The approach to move that automation away from Basic authentication is to use a non-interactive certificate-based logon using an Azure AD app-only configuration, which is documented here: App-only authentication in Exchange Online PowerShell and Security & Compliance PowerShell.

There is a small caveat here; using an Azure AD app-only configuration is tied to Exchange Online and Azure roles as shown below. This is great for most of the requirements you might have. For example, it allows the Exchange Administrator role assignment for a complete management access, or Exchange Recipient Administrator with the scope of Mail User Administrator and even Global Reader, which allows read-only access through the configured app.


In the past, customers using the concept of least privilege access often created customized Exchange Online admin roles, and haven´t been able to use the listed roles which would have extended today’s permissions for administrator or service accounts.

In most cases service accounts are used for non interactive logon scenarios. Moving this daemon use cases from today’s basic authentication to modern authentication implies the usage of Exchange Online certificate-based authentication. If the RBAC role permissions were needed, these service accounts couldn't be moved away from Basic authentication.

Great news, though! Customized RBAC roles in Exchange Online are now supported for use with an Azure AD app-only configuration using the v3 module and REST-based cmdlets. Check it out at App-only authentication for unattended scripts in Exchange Online PowerShell and Security & Complian.... This is not supported with the “-UseRPSSession” parameter when connecting to Exchange Online, but you shouldn’t need to use it because the v3 module supports all cmdlets using a REST-based API.

Let me show you how to configure this. The biggest change is the new ability to create Service Principal accounts (which I have also explained at Notes from the field: Using OAuth for ActiveSync and POP/IMAP in Exchange Online for IMAP/POP application access).

First, I create a custom RBAC role in Exchange Online as I’ve done in the past. In my example, it is a view-only role that can run only Get-Mailbox and no other cmdlets. I connect to Exchange Online PowerShell as an Organization Admin and create a new role based on the given default role View-Only Recipients and assign this new role to a role group to allow easy role assignment to a user or an Azure AD app.


New-ManagementRole -Name "Stripped View-Only Recipients" -Parent "View-Only Recipients
Get-ManagementRoleEntry "Stripped View-Only Recipients\*"| Where-Object { $_.Name -NotLike "Get-Mailbox" } | ForEach-Object {Remove-ManagementRoleEntry -Identity "$($\$($"}"
New-RoleGroup -Name 'ViewOnlyRecipients4CBA-Stripped' -Roles "Stripped View-Only Recipients"


This is the same approach you may have taken in the past for customized RBAC roles in Exchange Online. Next (following App-only authentication in Exchange Online PowerShell and Security & Compliance PowerShell), I create an Azure AD application with Exchange.ManageAsApp permission and a self-signed certificate.


Next, I connect the dots and assign the new role to the Azure AD application and then verify the admin permissions and available cmdlets. This is where a new cmdlet, New-ServicePrincipal can be used.

For further configuration, I need some details from the registered Azure AD App, so I am using Get-AzureADServicePrincipal in the AzureAD PowerShell module to get the needed information for using the New-ServicePrincipal with the right values. Dealing with Azure AD applications and service principals means dealing with a lot of different GUIDs, so make sure to use the right ones.


$ServicePrincipalDetails = Get-AzureADServicePrincipal -SearchString YourAppName
New-ServicePrincipal -AppId $ServicePrincipalDetails.AppId -ServiceId $ServicePrincipalDetails.ObjectId -DisplayName "EXO Serviceprincipal for AzureAD App $($ServicePrincipalDetails.Displayname)"


The new service principal is used in Exchange Online to grant permission to access mailboxes (using the Identity/ServiceId of the service principal and not the AppId).


After I’ve created the anchor object for the Azure AD application in Exchange Online, I assign a custom RBAC role to the service principal:


Add-RoleGroupMember -Identity "ViewOnlyRecipients4CBA-Stripped" -Member Identity/ServiceId of the Service principal.


Next, I connect using Exchange Online PowerShell with the configured certificate to verify that the session enables only the Get-Mailbox cmdlet. In the past, I would have used Get-PSSession to check for available cmdlets. In the v3, module Get-ConnectionInformation is used and produces output like this:


Thanks to Namrata Gupta, Pallavi Prashanth, Nino Bilic and Greg Taylor for quickly helping me with early feedback and testing options.

Danijel Klaric

Version history
Last update:
‎Dec 05 2022 07:33 AM
Updated by: