Exchange Online CBA One Way to Replace Basic Authentication
Updated 1-Nov-2023
The writing team for the Office 365 for IT Pros eBook very much appreciate the work done by our redoubtable technical editor, Vasil Michev, when he probes and questions text in the book chapters. It’s nice to get some of our own back when Vasil commits himself to print.
Take his article on certificate-based authentication for Exchange Online PowerShell. There’s a lot of good stuff here, but Vasil’s mind runs at such a fast rate that he sometimes omits details when he explains something that end up stopping people being able to master a topic. This is when people with slower CPUs, like me, step in to ask irritating questions.
Three Steps to Certificate-Based Authentication
Batch jobs that need to interact with Exchange Online PowerShell cannot use basic authentication any longer. The solution is to use certificate-based authentication instead. The mechanism might seem complex when you first read Microsoft’s instructions, but it can be boiled down to three points:
- An app registered with Entra ID. The app is the entry point to Exchange Online PowerShell because it is granted permission (as a service principal) to perform administrative actions. You might have used apps registered with Entra ID to interact with the Microsoft Graph where these apps hold the Graph API permissions necessary to access data.
- A self-signed X.509 certificate used to authenticate the application against Azure AD when access is needed.
- Microsoft 365 is a massive multi-tenant environment, so you need to tell Exchange Online which tenant to connect to be able to run PowerShell in a background process.
The same process to enable certificate-based authentication can be used with other Microsoft 365 modules that support certificate-based authentication such as the Microsoft Teams module.
Creating the App and Assigning Permissions and Role
Creating the app and assigning the necessary Exchange.AsManageApp permission and administrative role is quickly done in the Entra ID admin center. These are one-time operations that don’t need to be automated in code. However, it’s worth noting that role assignments can be made with PowerShell. It’s useful to know how to do this because you might use the technique in future to assign a role to a user.
This code fetches the object identifier for the app (it’s called “Exo Background process”) and assigns the Exchange Administrator directory role to the app.
$ExoAppSp = (Get-MgServicePrincipal -Filter "DisplayName eq 'Exo Background Process'").Id $ExoRoleId = (Get-MgDirectoryRole | Where-Object {$_.DisplayName -eq "Exchange Administrator"}).Id $NewAssignee = @{ "@odata.id" = ("https://graph.microsoft.com/v1.0/directoryObjects/{0}" -f $ExoAppSp) } New-MgDirectoryRoleMemberByRef -DirectoryRoleId $ExoRoleId -BodyParameter $NewAssignee
The same approach is used to assign a role to a user. The difference is that the object identifier for the user is fetched with the Get-MgUser cmdlet. This example shows how to assign the Global Reader role to a user.
$UserId = (Get-MgUser -UserId Otto.Flick@Office365itpros.com).Id $RoleId = (Get-MgDirectoryRole | Where-Object {$_.DisplayName -eq "Global Reader"}).Id $NewAssignee = @{ "@odata.id" = ("https://graph.microsoft.com/v1.0/directoryObjects/{0}" -f $UserId) } New-MgDirectoryRoleMemberByRef -DirectoryRoleId $RoleId -BodyParameter $NewAssignee
With that diversion taken care of, we can proceed to obtaining a self-signed X.509 certificate, which is where people sometimes become stuck (I did).
Creating the Certificate
You need to upload a suitable X.509 self-signed certificate to the Azure AD app to create an association between the two. Certificates are not the easiest of objects to work with, but in this case it’s straightforward.
If you don’t have a suitable certificate to hand, you must generate one. Vasil was short on detail on this point (until I asked him how he had generated a certificate). Microsoft recommends using either the Create-SelfSignedCertificate.ps1 script or the MakeCert command-line utility. These are certainly viable options, but the easiest way is to run the New-SelfSignedCertificate cmdlet using a command like this:
New-SelfSignedCertificate -Subject "Exo Background Process" -CertStoreLocation "cert:\CurrentUser\My" -KeySpec KeyExchange -FriendlyName "For EXO V2 Background Jobs"
This command creates a certificate valid for a year in the personal store of the user, which is fine for testing (Figure 1). Obviously, in a production environment, you’d create the certificate in the personal store of the account that will be used to run batch jobs.

To associate the certificate with the app, export the certificate as a DER-encoded binary X.509 file (Figure 2). You can call the file anything you like, but you should give it a .CER extension.

Finally, upload the exported file to the app in the Azure AD portal. This will generate a thumbprint that you need to note (Figure 3).

Bringing it Together with Exchange Online CBA
After setting up the app, the three vital pieces of information we need to connect are:
- The AppId of the application you created.
- The thumbprint of the certificate loaded into the app.
- The service domain for your tenant (like tenant.onmicrosoft.com).
With these values, you can connect to Exchange Online using certificate-based authentication with a command like:
Connect-ExchangeOnline -CertificateThumbprint "40EED7993F65D8CF13D5ABAC87F3AAD307012D22" -AppId "b83c46c6-044e-40e5-929c-634f80045a11" -ShowBanner:$false -Organization tenant.onmicrosoft.com
There are obviously more complications that await the unwary along the way, but this is enough to connect and play with Exchange Online PowerShell in batch jobs. Vasil’s post contains a lot of detail and there will be more articles and guidance published as we approach the deadline for basic authentication to disappear next year, which is a good reason to subscribe to a reliable source of information like the Office 365 for IT Pros eBook.