Share via


Configure OAuth authentication between Exchange and Exchange Online organizations

The Hybrid Configuration wizard automatically configures OAuth authentication between Exchange Server on-premises and Exchange Online organizations. If your Exchange organization contains Exchange 2010 or Exchange 2007 servers, the Hybrid Configuration wizard doesn't configure OAuth authentication between the on-premises and online Exchange organizations. These deployments continue to use the federation trust process by default. However, certain features are only fully available across your organization by using the new Exchange OAuth authentication protocol.

The new Exchange OAuth authentication process currently enables the following Exchange features:

  • Message Records Management (MRM)
  • Exchange In-place eDiscovery
  • Exchange In-place Archiving

We recommend that all mixed Exchange 2013 organizations configure Exchange OAuth authentication after running the Hybrid Configuration Wizard.

Important

  • If your on-premises organization is running only Exchange 2013 servers with Cumulative Update 5 or later, Exchange 2016 or Exchange 2019, run the Hybrid Configuration Wizard instead of performing the steps in this topic.

  • This feature of Exchange Server 2013 isn't fully compatible with Office 365 operated by 21Vianet in China and some feature limitations may apply. For more information, see Office 365 operated by 21Vianet.

What do you need to know before you begin?

Tip

Having problems? Ask for help in the Exchange forums. Visit the forums at Exchange Server.

How do you configure OAuth authentication between your on-premises Exchange and Exchange Online organizations?

Glossary

Initial domain: The first domain provisioned in the tenant. For example, contoso.onmicrosoft.com. It's referred to as <your tenant initial domain> in this documentation.

Hybrid routing domain: The hybrid routing domain in Exchange hybrid environments, like contoso.mail.onmicrosoft.com, is used to manage mail flow between on-premises Exchange servers and Exchange Online. It ensures seamless communication and message delivery across both environments. It's referred to as <your hybrid routing domain> in this documentation.

Microsoft Online Email Routing Address (MOERA): The address constructed from the user's userPrincipalName prefix, plus the initial domain suffix, which is automatically added to the proxyAddress in Microsoft Entra ID. For example, smtp:[email protected]. We do not use the MOERA in this documentation but list it here for the sake of completeness.

Primary SMTP domain: The primary SMTP domain in Microsoft Exchange Server is the main domain used for email addresses within the organization. It's referred to as <your primary SMTP domain> in this documentation.

AutoDiscover endpoint: The AutoDiscover endpoint is a web service URL that provides Exchange Server configuration information. It enables applications to automatically discover and connect to Exchange services. If your company uses, for example, contoso.com as primary SMTP domain, the AutoDiscover endpoint is usually https://autodiscover.contoso.com/autodiscover/autodiscover.svc or https://contoso.com/autodiscover/autodiscover.svc. It's referred to as <your on-premises AutoDiscover endpoint> in this documentation.

Exchange Web Services (EWS): Exchange Web Services (EWS) is a cross-platform API that enables applications to access mailbox items such as email messages, meetings, and contacts. It's referred to as <your on-premises external Exchange Web Services URL> in this documentation.

Step 1: Create the authorization server objects for your Exchange Online organization

Run the following command in the Exchange Management Shell (Exchange PowerShell) in your on-premises Exchange organization. Make sure to replace the placeholders with your values before you run the command:

New-AuthServer -Name "WindowsAzureACS" -AuthMetadataUrl "https://accounts.accesscontrol.windows.net/<your tenant initial domain>/metadata/json/1"
New-AuthServer -Name "evoSTS" -Type AzureAD -AuthMetadataUrl "https://login.windows.net/<your tenant initial domain>/federationmetadata/2007-06/federationmetadata.xml"

In GCC High or DoD, you need to use the following commands instead:

New-AuthServer -Name "WindowsAzureACS" -AuthMetadataUrl "https://login.microsoftonline.us/<your tenant initial domain>/metadata/json/1"
New-AuthServer -Name "evoSTS" -Type AzureAD -AuthMetadataUrl "https://login.microsoftonline.us/<your tenant initial domain>/federationmetadata/2007-06/federationmetadata.xml"

Step 2: Enable the partner application for your Exchange Online organization

Run the following command in the Exchange PowerShell in your on-premises Exchange organization:

Get-PartnerApplication |  Where-Object {$_.ApplicationIdentifier -eq "00000002-0000-0ff1-ce00-000000000000" -and $_.Realm -eq ""} | Set-PartnerApplication -Enabled $true

Step 3: Export the on-premises authorization certificate

In this step, you have to run a PowerShell script on the Exchange server directly to export the on-premises authorization certificate, which is then imported to your Exchange Online organization in the next step.

  1. Save the following text to a PowerShell script file named, for example, ExportAuthCert.ps1.

    Note

    If you want to upload the certificate which is configured to become the new auth certificate in future, replace $thumbprint = (Get-AuthConfig).CurrentCertificateThumbprint with $thumbprint = (Get-AuthConfig).NewCertificateThumbprint.

    $thumbprint = (Get-AuthConfig).CurrentCertificateThumbprint
    if((Test-Path $env:SYSTEMDRIVE\OAuthConfig) -eq $false)
    {
       New-Item -Path $env:SYSTEMDRIVE\OAuthConfig -Type Directory
    }
    Set-Location -Path $env:SYSTEMDRIVE\OAuthConfig
    $oAuthCert = (dir Cert:\LocalMachine\My) | Where-Object {$_.Thumbprint -match $thumbprint}
    $certType = [System.Security.Cryptography.X509Certificates.X509ContentType]::Cert
    $certBytes = $oAuthCert.Export($certType)
    $CertFile = "$env:SYSTEMDRIVE\OAuthConfig\OAuthCert.cer"
    [System.IO.File]::WriteAllBytes($CertFile, $certBytes)
    
  2. In Exchange PowerShell in your on-premises Exchange organization, run the PowerShell script that you created in the previous step. For example:

    .\ExportAuthCert.ps1
    

Step 4: Upload the on-premises authorization certificate to Microsoft Entra Access Control Service (ACS)

Next, use the Microsoft Graph PowerShell to upload the on-premises authorization certificate that you exported in the previous step to Microsoft Entra Access Control Services (ACS). If you don't have the module installed, open a Windows PowerShell window as an administrator and run the following command:

Install-Module -Name Microsoft.Graph.Applications

Complete the following steps after the Microsoft Graph PowerShell is installed.

  1. Open a Windows PowerShell workspace that has the Microsoft Graph cmdlets installed. All commands in this step will be run using the Windows PowerShell connected to Microsoft Graph console.

  2. Save the following text to a PowerShell script file named, for example, UploadAuthCert.ps1.

    Connect-MgGraph -Scopes Application.ReadWrite.All
    
    $CertFile = "$env:SYSTEMDRIVE\OAuthConfig\OAuthCert.cer"
    $objFSO = New-Object -ComObject Scripting.FileSystemObject
    $CertFile = $objFSO.GetAbsolutePathName($CertFile)
    $cer = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($CertFile)
    $binCert = $cer.GetRawCertData()
    $credValue = [System.Convert]::ToBase64String($binCert)
    $ServiceName = "00000002-0000-0ff1-ce00-000000000000"
    Write-Host "[+] Trying to query the service principals for service: $ServiceName" -ForegroundColor Cyan
    $p = Get-MgServicePrincipal -Filter "AppId eq '$ServiceName'"
    Write-Host "[+] Trying to query the keyCredentials for service: $ServiceName" -ForegroundColor Cyan
    $servicePrincipalKeyInformation = Get-MgServicePrincipal -Filter "AppId eq '$ServiceName'" -Select "keyCredentials"
    
    $keyCredentialsLength = $servicePrincipalKeyInformation.KeyCredentials.Length
    if ($keyCredentialsLength -gt 0) {
       Write-Host "[+] $keyCredentialsLength existing key(s) found - we keep them if they have not expired" -ForegroundColor Cyan
    
       $newCertAlreadyExists = $false
       $servicePrincipalObj = New-Object -TypeName Microsoft.Graph.PowerShell.Models.MicrosoftGraphServicePrincipal
       $keyCredentialsArray = @()
    
       foreach ($cred in $servicePrincipalKeyInformation.KeyCredentials) {
          $thumbprint = [System.Convert]::ToBase64String($cred.CustomKeyIdentifier)
    
          Write-Host "[+] Processing existing key: $($cred.DisplayName) thumbprint: $thumbprint" -ForegroundColor Cyan
    
          if ($newCertAlreadyExists -ne $true) {
             $newCertAlreadyExists = ($cer.Thumbprint).Equals($thumbprint, [System.StringComparison]::OrdinalIgnoreCase)
          }
    
          if ($cred.EndDateTime -lt (Get-Date)) {
             Write-Host "[+] This key has expired on $($cred.EndDateTime) and will not be retained" -ForegroundColor Yellow
             continue
          }
    
          $keyCredential = New-Object -TypeName Microsoft.Graph.PowerShell.Models.MicrosoftGraphKeyCredential
          $keyCredential.Type = "AsymmetricX509Cert"
          $keyCredential.Usage = "Verify"
          $keyCredential.Key = $cred.Key
    
          $keyCredentialsArray += $keyCredential
       }
    
    
       if ($newCertAlreadyExists -eq $false) {
          Write-Host "[+] New key: $($cer.Subject) thumbprint: $($cer.Thumbprint) will be added" -ForegroundColor Cyan
          $keyCredential = New-Object -TypeName Microsoft.Graph.PowerShell.Models.MicrosoftGraphKeyCredential
          $keyCredential.Type = "AsymmetricX509Cert"
          $keyCredential.Usage = "Verify"
          $keyCredential.Key = [System.Text.Encoding]::ASCII.GetBytes($credValue)
    
          $keyCredentialsArray += $keyCredential
    
          $servicePrincipalObj.KeyCredentials = $keyCredentialsArray
          Update-MgServicePrincipal -ServicePrincipalId $p.Id -BodyParameter $servicePrincipalObj
       } else {
          Write-Host "[+] New key: $($cer.Subject) thumbprint: $($cer.Thumbprint) already exists and will not be uploaded again" -ForegroundColor Yellow
       }
    } else {
       $params = @{
          type = "AsymmetricX509Cert"
          usage = "Verify"
          key = [System.Text.Encoding]::ASCII.GetBytes($credValue)
       }
    
       Write-Host "[+] This is the first key which will be added to this service principal" -ForegroundColor Cyan
       Update-MgServicePrincipal -ServicePrincipalId $p.Id -KeyCredentials $params
    }
    
  3. Run the PowerShell script that you created in the previous step. For example:

    .\UploadAuthCert.ps1
    
  4. After you start the script, a credentials dialog box is displayed. Enter the credentials for the tenant administrator account in your Microsoft Online Microsoft Entra organization. After running the script, leave the Windows PowerShell connected to Microsoft Graph session open. You will use this to run a PowerShell script in the next step.

Step 5: Register all hostname authorities for your internal and external on-premises Exchange HTTP endpoints with Microsoft Entra ID

You need to run the script in this step for each publicly accessible endpoint in your on-premises Exchange organization, including Internal and External URLs for Hybrid Modern Authentication). For example, if Exchange is externally available at https://mail.contoso.com/ews/exchange.asmx, use the service principal name https://mail.contoso.com. There isn't a limit for registering additional external hostname authorities.

To confirm the Exchange endpoints in your on-premises organization, run the following commands in the Exchange Management Shell:

Get-MapiVirtualDirectory | Format-List server,*url*
Get-WebServicesVirtualDirectory | Format-List server,*url*
Get-OABVirtualDirectory | Format-List server,*url*

Note

The following script requires that the Windows PowerShell connected to Microsoft Graph is connected to your Microsoft 365 organization, as explained in step 4 in the previous section.

  1. Save the following text to a PowerShell script file named, for example, RegisterEndpoints.ps1. Replace https://mail.contoso.com/ and https://autodiscover.contoso.com/ with the appropriate hostname authority for your on-premises Exchange organization.

     $ServiceName = "00000002-0000-0ff1-ce00-000000000000";
     $x = Get-MgServicePrincipal -Filter "AppId eq '$ServiceName'"
     $x.ServicePrincipalNames += "https://mail.contoso.com/"
     $x.ServicePrincipalNames += "https://autodiscover.contoso.com/"
     Update-MgServicePrincipal -ServicePrincipalId $x.Id -ServicePrincipalNames $x.ServicePrincipalNames
    
  2. In Windows PowerShell connected to Microsoft Graph, run the Windows PowerShell script that you created in the previous step. For example:

    .\RegisterEndpoints.ps1
    
  3. To verify that all the records were added, run the following command in Windows PowerShell connected to Microsoft Graph and look for https://namespace entries in the results.

    Get-MgServicePrincipal -Filter "AppId eq '$ServiceName'" | Select-Object -ExpandProperty ServicePrincipalNames | Sort-Object
    

Step 6: Create an IntraOrganizationConnector from your on-premises organization to Microsoft 365 or Office 365

In this step, we configure an IntraOrganizationConnector that allows Exchange Server on-premises to reach your Exchange Online organization. This connector enables feature availability and service connectivity across the organizations. You can use the Get-IntraOrganizationConfiguration cmdlet in both your on-premises and Microsoft 365 or Office 365 tenants to determine the endpoint values needed by New-IntraOrganizationConnector cmdlet.

We configure the hybrid routing domain as target address. The hybrid routing domain is created automatically when your Microsoft 365 or Office 365 organization is created. For example, if the first domain that was added and validated in the Microsoft 365 or Office 365 organization is contoso.com, your target address would be contoso.mail.onmicrosoft.com.

Using Exchange PowerShell, run the following cmdlet in your on-premises organization:

$ServiceDomain = (Get-AcceptedDomain | Where-Object {$_.DomainName -like "*.mail.onmicrosoft.com"}).DomainName.Address
New-IntraOrganizationConnector -Name ExchangeHybridOnPremisesToOnline -DiscoveryEndpoint https://outlook.office365.com/autodiscover/autodiscover.svc -TargetAddressDomains $ServiceDomain

Step 7: Create an IntraOrganizationConnector from your Microsoft 365 or Office 365 organization to your on-premises Exchange organization

In this step, we configure an IntraOrganizationConnector that allows Exchange Online to reach your on-premises Exchange organization. This connector enables feature availability and service connectivity across the organizations. You can use the Get-IntraOrganizationConfiguration cmdlet in both your on-premises and Microsoft 365 or Office 365 tenants to determine the endpoint values needed by New-IntraOrganizationConnector cmdlet.

You should add all SMTP domains that are used in your Exchange on-premises organization (except your initial domain and hybrid routing domain) as TargetAddressDomains. If you have multiple SMTP domains, add them as a comma-separated list (for example, contoso.com,tailspintoys.com). You also need to provide your on-premises AutoDiscover endpoint as DiscoveryEndpoint.

After you connect to Exchange Online PowerShell, replace <your on-premises AutoDiscover endpoint> and <your on-premises SMTP domain(s)> with your values and run the following command:

New-IntraOrganizationConnector -Name ExchangeHybridOnlineToOnPremises -DiscoveryEndpoint <your on-premises AutoDiscover endpoint> -TargetAddressDomains <your on-premises SMTP domain(s)>

Step 8: Configure an AvailabilityAddressSpace for any pre-Exchange 2013 SP1 servers

Warning

Exchange Server 2007, Exchange Server 2010 and Exchange Server 2013 have reached the end of support.

When you configure a hybrid deployment in older Exchange organizations, you need at least one Exchange 2013 server that's running Exchange 2013 SP1 or later. The Exchange 2013 server requires the Client Access and Mailbox server roles. The Exchange 2013 server coordinates communications between your existing Exchange on-premises organization and the Exchange Online organization. We highly recommend installing more than one Exchange 2013 server in your on-premises organization to help increase reliability and availability of hybrid deployment features.

In Exchange 2013 organizations with Exchange 2010 or Exchange 2007, we recommended that all Internet-facing frontend servers are Exchange 2013 Client Access servers running SP1 or later. All Exchange Web Services (EWS) requests must go through an Exchange 2013 Client Access server. This requirement includes requests from Microsoft 365 to your on-premises Exchange organization, and requests from your on-premises Exchange organization to Microsoft 365. It's important that you have enough Exchange 2013 Client Access servers to handle the processing load and to provide connection redundancy. The number of Client Access servers you need depends on the average amount of EWS requests, and varies by organization.

Before you complete the following step, make sure:

  • The frontend hybrid servers are Exchange 2013 SP1 or greater.
  • You have a unique external EWS URL for the Exchange 2013 server(s). The Microsoft 365 or Office 365 organization must connect to these servers in order for cloud-based requests for hybrid features to work correctly.
  • The servers have both the Mailbox and Client Access server roles
  • Any existing Exchange 2010/2007 Mailbox and Client Access servers have the latest Cumulative Update (CU) or Service Pack (SP) applied.

Note

Existing Exchange 2010/2007 Mailbox servers can continue to use Exchange 2010/2007 Client Access servers for frontend servers for non-hybrid feature connections. Only hybrid deployment feature requests from the Microsoft 365 or Office 365 organization need to connect to Exchange 2013 servers.

An AvailabilityAddressSpace must be configured on pre-Exchange 2013 Client Access servers that points to the Exchange Web Services endpoint of your on-premises Exchange 2013 SP1 Client Access server(s). This endpoint is the same endpoint as previously outlined in Step 5 or can be determined by running the following cmdlet on your on-premises Exchange 2013 SP1 Client Access server:

Get-WebServicesVirtualDirectory | Format-List AdminDisplayVersion,ExternalUrl

Note

If virtual directory information is returned from multiple servers, make sure you use the endpoint returned for an Exchange 2013 SP1 Client Access server. It will display 15.0 (Build 847.32) or higher for the AdminDisplayVersion parameter.

To configure the AvailabilityAddressSpace, use Exchange PowerShell and run the following cmdlet in your on-premises organization:

Add-AvailabilityAddressSpace -AccessMethod InternalProxy -ProxyUrl <your on-premises external Exchange Web Services URL> -ForestName <your hybrid routing domain> -UseServiceAccount $true

How do you know this worked?

You can verify that the OAuth configuration is correct by using the Test-OAuthConnectivity cmdlet. This cmdlet verifies that the on-premises Exchange and Exchange Online endpoints can successfully authenticate requests from each other.

To verify that your on-premises Exchange organization can successfully connect to Exchange Online, run the following command in Exchange PowerShell in your on-premises organization:

Test-OAuthConnectivity -Service EWS -TargetUri https://outlook.office365.com/ews/exchange.asmx -Mailbox <On-Premises Mailbox> -Verbose | Format-List

To verify that your Exchange Online organization can successfully connect to your on-premises Exchange organization, connect to Exchange Online PowerShell and run the following command:

Test-OAuthConnectivity -Service EWS -TargetUri <external hostname authority of your Exchange On-Premises deployment>/metadata/json/1 -Mailbox <Exchange Online Mailbox> -Verbose | Format-List

Example:

Test-OAuthConnectivity -Service EWS -TargetUri `https://mail.contoso.com/metadata/json/1` -Mailbox ExchangeOnlineBox1 -Verbose | Format-List

Important

You can ignore the The SMTP address has no mailbox associated with it. error. It's only important that the ResultTask parameter returns a value of Success. For example, the last section of the test output should read:

ResultType: Success
Identity: Microsoft.Exchange.Security.OAuth.ValidationResultNodeId
IsValid: True
ObjectState: New