Connecting to Office 365 online mail with OAUTH 2.0 authentication always failed !

Copper Contributor

1 Issue Description

       There is an connecting issue using OAuth 2.0 to connect Office 365 mail server . I'm following the guide  to get access token and using the token to connect Exchange server . it always throw error about  authentication failed .  Is the permission configuration issue ? The permission which I configured as below  (sensitive message has been hidden)

     

Bland_Wu_0-1614235959175.png

 

   Could you please give some help if you have some experience or meet the issue like this ? Thanks !

 

2 Core Code (Java , using javamail 1.6.2)

   

Properties props = System.getProperties();
 props.put("mail.imaps.auth.mechanisms","XOAUTH2");
 props.put("mail.imaps.port", "993");
 props.put("mail.imaps.starttls.enable", "true");
 props.put("mail.imaps.auth", "true");
 props.put("mail.imaps.host","outlook.office365.com");
 props.setProperty("mail.transport.protocol", "imaps");
 props.setProperty("mail.store.protocol", "imaps");
 props.setProperty("mail.debug.auth","true");
        
 Session session = Session.getInstance(props);		
 IMAPStore store = (IMAPStore)session.getStore("imaps");
 String userEmail = "****";
 String accessToken = "****"; 
 store.connect(userEmail,accessToken);		

   

3 Error Message

   

DEBUG: getProvider() returning javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle]
DEBUG IMAPS: mail.imap.fetchsize: 16384
DEBUG IMAPS: mail.imap.ignorebodystructuresize: false
DEBUG IMAPS: mail.imap.statuscachetimeout: 1000
DEBUG IMAPS: mail.imap.appendbuffersize: -1
DEBUG IMAPS: mail.imap.minidletime: 10
DEBUG IMAPS: enable STARTTLS
DEBUG IMAPS: closeFoldersOnStoreFailure
DEBUG IMAPS: trying to connect to host "outlook.office365.com", port 993, isSSL true
* OK The Microsoft Exchange IMAP4 service is ready. [SABLAEEAUABSADAAMwBDAEEAMAAwADEAMQAuAGEAcABjAHAAcgBkADAAMwAuAHAAcgBvAGQALgBvAHUAdABsAG8AbwBrAC4AYwBvAG0A]
A0 CAPABILITY
* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=XOAUTH2 SASL-IR UIDPLUS MOVE ID UNSELECT CHILDREN IDLE NAMESPACE LITERAL+
A0 OK CAPABILITY completed.
DEBUG IMAPS: AUTH: PLAIN
DEBUG IMAPS: AUTH: XOAUTH2
DEBUG IMAPS: protocolConnect login, host=outlook.office365.com, user=****@****.com, password=<non-null>
A1 AUTHENTICATE XOAUTH2 dXNlcj1jY2NfYXNzaXN0YW50X3VhdEBzeW5uZXguY29tAWF1dGg9QmVhcmVyIGV5SjBlWEFpT2lKS1YxUWlMQ0p1YjI1alpTSTZJbVJqT1RNeU1WbE1SMFpIYTFvemFUQTNTalJ3VWxwcGNFMU9lbUUwV1MxSWNpMVhValo1ZUhCWE0yTWlMQ0poYkdjaU9pSlNVekkxTmlJc0luZzFkQ0k2SW01UGJ6TmFSSEpQUkZoRlN6RnFTMWRvV0hOc1NGSmZTMWhGWnlJc0ltdHBaQ0k2SW01UGJ6TmFSSEpQUkZoRlN6RnFTMWRvV0hOc1NGSmZTMWhGWnlKOS5leUpoZFdRaU9pSm9kSFJ3Y3pvdkwyZHlZWEJvTG0xcFkzSnZjMjltZEM1amIyMGlMQ0pwYzNNaU9pSm9kSFJ3Y3pvdkwzTjBjeTUzYVc1a2IzZHpMbTVsZEM4NU56SmhNR1V5Tnkxak16VTFMVFJtWkRjdE9USXlOUzA1TWpZMll6aG1Nek15WVdNdklpd2lhV0YwSWpveE5qRTBNak16TURZMUxDSnVZbVlpT2pFMk1UUXlNek13TmpVc0ltVjRjQ0k2TVRZeE5ESXpOamsyTlN3aVlXbHZJam9pUlRKYVoxbElhRko0U0VNemVXSkljRFZKTUN0c1dHTjZiblUzWjBGQlFUMGlMQ0poY0hCZlpHbHpjR3hoZVc1aGJXVWlPaUpxYzJRZ1pXMWhhV3dnYUdGdVpHeGxjaUIxWVhRaUxDSmhjSEJwWkNJNklqVTFabUU0WWpsaExUVXdPREl0TkdSallpMDVOekppTFdKa09Ua3daRFUzTmpVMU5TSXNJbUZ3Y0dsa1lXTnlJam9pTVNJc0ltbGtjQ0k2SW1oMGRIQnpPaTh2YzNSekxuZHBibVJ2ZDNNdWJtVjBMemszTW1Fd1pUSTNMV016TlRVdE5HWmtOeTA1TWpJMUxUa3lOalpqT0dZek16SmhZeThpTENKcFpIUjVjQ0k2SW1Gd2NDSXNJbTlwWkNJNklqVmpNR1UyT0RWbUxXWmlPRFF0TkRjNU55MDRaalptTFRjek1URm1ZMlV5TW1aa09DSXNJbkpvSWpvaU1DNUJRVUZCU25jMGNXd3hXRVF4TUMxVFNscEtiWGxRVFhseVNuRk1MV3hYUTFWTmRFNXNlWFU1YlZFeFdGcFdWVTlCUVVFdUlpd2ljM1ZpSWpvaU5XTXdaVFk0TldZdFptSTROQzAwTnprM0xUaG1ObVl0TnpNeE1XWmpaVEl5Wm1RNElpd2lkR1Z1WVc1MFgzSmxaMmx2Ymw5elkyOXdaU0k2SWs1Qklpd2lkR2xrSWpvaU9UY3lZVEJsTWpjdFl6TTFOUzAwWm1RM0xUa3lNalV0T1RJMk5tTTRaak16TW1Gaklpd2lkWFJwSWpvaVVtbGhZMDlwV2kxNGF5MWhjMEpWUWs0eU9GTkJRU0lzSW5abGNpSTZJakV1TUNJc0luaHRjMTkwWTJSMElqb3hNemN4TnpJNE5UazRmUS5mTkJxeVlzSkh4SGNQOUtuNnA0RFNsdjUwRmlkV1cyaTd2X2h1dnM4WDFkN29XcmM5d3RaUVg2UFZ6LXF6ZkotMVRiR09FVGIweXdfbVZ0bEJEWjJPcmFzWnFORF9XNUttb0ZTZGpVV1VBNjdDdVZQdkl1WkdCWTVFM2I3MDBGZTBCLWdDdnQzUDJSekxQOWsxbkFUTTZmQ09tYldpZDd2WklHaFlKU1czZHlJX0lkcV9Oa1d2Mk96NU9rLXNRNThNaXFiZzZqWlNYZUEzUTdKVXNuUFBBX2Z2dFVhLWUyV25RRFlZYktvcDl1WWdick9TM3NOYS1OajNXMkxvQnhWVU80NHVNZC0tak5TMEtuN2xjUkY5cW5NbEE5OFJCTE42V3I0clBYMGZtMjZrNG9MYjU4RFAycFZraG4tOW5MZFFwcXZkbTZ1cGJ1OEZabkd1NkNXVHcBAQ==
A1 NO AUTHENTICATE failed.
2021-02-25 14:09:38.935 ERROR 10416 --- [nio-9000-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is javax.mail.AuthenticationFailedException: AUTHENTICATE failed.] with root cause

javax.mail.AuthenticationFailedException: AUTHENTICATE failed.
	at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:732) ~[javax.mail-1.6.2.jar:1.6.2]
	at javax.mail.Service.connect(Service.java:366) ~[javax.mail-api-1.6.2.jar:1.6.2]
	at javax.mail.Service.connect(Service.java:246) ~[javax.mail-api-1.6.2.jar:1.6.2]
	at javax.mail.Service.connect(Service.java:267) ~[javax.mail-api-1.6.2.jar:1.6.2]
	at com.compony.service.impl.RestServiceImpl.connectOffice365Mail(RestServiceImpl.java:102) ~[classes/:na]
	at com.compony.controller.IndexController.testEmail(IndexController.java:50) ~[classes/:na]
	at com.compony.controller.IndexController$$FastClassBySpringCGLIB$$830877a4.invoke(<generated>) ~[classes/:na]
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:119) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691) ~[spring-aop-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at com.compony.controller.IndexController$$EnhancerBySpringCGLIB$$87a3038.testEmail(<generated>) ~[classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_91]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_91]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_91]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.38.jar:4.0.FR]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.38.jar:4.0.FR]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.38.jar:9.0.38]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123) ~[druid-1.1.10.jar:1.1.10]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.9.RELEASE.jar:5.2.9.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) [tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) [tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590) [tomcat-embed-core-9.0.38.jar:9.0.38]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.38.jar:9.0.38]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_91]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_91]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.38.jar:9.0.38]
	at java.lang.Thread.run(Thread.java:745) [na:1.8.0_91]		

 

5 Replies
Was a solution this this ever found? I have been having the same issue.

@Bland_Wu Having the exact same issue and have tried to get in contact with Microsoft support to solve this without any luck. I use msal4j to get the access token which seems ok (sending the scope https://graph.microsoft.com/.default, sending any other scope will fail for me) but the access token returned have scope null but don't know if that is the issue.

 

Basically using the same attempt to connect with IMAP, a sample code below

String strClientID = "REMOVED ON PURPOSE";
String strClientSecret = "REMOVED ON PURPOSE";
String strTenant = "REMOVED ON PURPOSE";

Set<String> lstScope = new HashSet<>();
lstScope.add("https://graph.microsoft.com/.default");
IClientCredential cred = ClientCredentialFactory.createFromSecret(strClientSecret);
String AUTHORITY = "https://login.microsoftonline.com/" + strTenant + "/";
ConfidentialClientApplication cca = ConfidentialClientApplication.builder(strClientID, cred)
.authority(AUTHORITY).build();
ClientCredentialParameters parameters = ClientCredentialParameters.builder(lstScope).build();
IAuthenticationResult token = cca.acquireToken(parameters).join();

/* We have a token, this seems to work fine even though scope in the below print out will give 'null' */
System.out.println("We have token: " + token.accessToken());
System.out.println("Scope: " + token.scopes());
System.out.println("Expires: " + token.expiresOnDate());

/* Connect with IMAP */
Properties props = new Properties();
props.put("mail.debug.auth", Boolean.TRUE);
props.put("mail.event.scope", "session");
props.put("mail.imaps.starttls.enable", Boolean.TRUE);
props.put("mail.imaps.ssl.enable", Boolean.TRUE);
props.put("mail.imaps.host", "outlook.office365.com");
props.put("mail.imaps.port", "993");
props.put("mail.imaps.sasl.enable", Boolean.TRUE);
props.put("mail.imaps.auth.mechanisms", "XOAUTH2");
props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
props.put("mail.imaps.auth.login.disable", Boolean.TRUE);
props.put("mail.imaps.auth.plain.disable", Boolean.TRUE);
props.put("mail.imaps.usesocketchannels", Boolean.TRUE);
props.put("mail.imaps.sasl.mechanisms.oauth2.oauthToken", token.accessToken());
Session session = Session.getInstance(props, null);
session.setDebug(true);
session.setDebugOut(System.out);
IMAPStore store = (IMAPStore) session.getStore("imaps");
store.setUsername("EMAIL ADDRESS HERE"); 
store.setPassword(token.accessToken());
store.connect();

 

Result: always fails with

NO AUTHENTICATE failed.

 

Has anyone got this to work? 

@JLund75 this may have to do with the way the app is setup in Azure and Exchange.  I use this script all the time (it's from MS), it will create the app, setup a group, add the user (identity sending the email) to the group, and permission it to use Exchange and send mail (the only user that can use it will be in the group).  You need to run it as a Global Admin.  In the end, it will give you the App ID and client secret.  I want to get my opencart site setup with this, let me know if this helps or if I'm way off base.

#------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation.  All rights reserved.
# Script to create AzureADApplication 'Microsoft Identity Manager Service Mailbox client' for Exchange Online authorization in MIM.
#------------------------------------------------------------------------------------------------------

Param 
    (
        [PSCredential] $Credential,
        [Parameter(Mandatory=$False, HelpMessage='Tenant ID (This is a GUID which represents the "Directory ID" of the AzureAD tenant into which you want to create the apps')]
        [string] $TenantId,
        [string] $AzureEnvironmentName,
        [Parameter(Mandatory=$True, HelpMessage='Mailbox Account Email')]
        [string] $MailboxAccountEmail
    )

# Create a password that could be used as an application key
Function ComputePassword
{
    $aesManaged = New-Object "System.Security.Cryptography.AesManaged"
    $aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CBC
    $aesManaged.Padding = [System.Security.Cryptography.PaddingMode]::Zeros
    $aesManaged.BlockSize = 128
    $aesManaged.KeySize = 256
    $aesManaged.GenerateKey()
    return [System.Convert]::ToBase64String($aesManaged.Key)
}

# Create an application key
Function CreateAppKey([DateTime] $fromDate, [double] $durationInYears, [string]$pw)
{
    $endDate = $fromDate.AddYears($durationInYears) 
    $keyId = (New-Guid).ToString();
    $key = New-Object Microsoft.Open.AzureAD.Model.PasswordCredential
    $key.StartDate = $fromDate
    $key.EndDate = $endDate
    $key.Value = $pw
    $key.KeyId = $keyId
    return $key
}

# Adds the requiredAccesses (expressed as a pipe separated string) to the requiredAccess structure
# The exposed permissions are in the $exposedPermissions collection, and the type of permission (Scope | Role) is 
# described in $permissionType
Function AddResourcePermission($requiredAccess, `
                               $exposedPermissions, [string]$requiredAccesses, [string]$permissionType)
{
    foreach($permission in $requiredAccesses.Trim().Split("|"))
    {
        foreach($exposedPermission in $exposedPermissions)
        {
            if ($exposedPermission.Value -eq $permission)
            {
                $resourceAccess = New-Object Microsoft.Open.AzureAD.Model.ResourceAccess
                $resourceAccess.Type = $permissionType # Scope = Delegated permissions | Role = Application permissions
                $resourceAccess.Id = $exposedPermission.Id # Read directory data
                $requiredAccess.ResourceAccess.Add($resourceAccess)
             }
        }
    }
}

# Exemple: GetRequiredPermissions "Microsoft Graph"  "Graph.Read|User.Read"
Function GetRequiredPermissions([string] $applicationDisplayName, [string] $requiredDelegatedPermissions, [string]$requiredApplicationPermissions, $servicePrincipal)
{
    # If we are passed the service principal we use it directly, otherwise we find it from the display name (which might not be unique)
    if ($servicePrincipal)
    {
        $sp = $servicePrincipal
    }
    else
    {
        $sp = Get-AzureADServicePrincipal -Filter "DisplayName eq '$applicationDisplayName'"
    }
    $appid = $sp.AppId
    $requiredAccess = New-Object Microsoft.Open.AzureAD.Model.RequiredResourceAccess
    $requiredAccess.ResourceAppId = $appid
    $requiredAccess.ResourceAccess = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.ResourceAccess]

    # $sp.Oauth2Permissions | Select Id,AdminConsentDisplayName,Value: To see the list of all the Delegated permissions for the application:
    if ($requiredDelegatedPermissions)
    {
        AddResourcePermission $requiredAccess -exposedPermissions $sp.Oauth2Permissions -requiredAccesses $requiredDelegatedPermissions -permissionType "Scope"
    }
    
    # $sp.AppRoles | Select Id,AdminConsentDisplayName,Value: To see the list of all the Application permissions for the application
    if ($requiredApplicationPermissions)
    {
        AddResourcePermission $requiredAccess -exposedPermissions $sp.AppRoles -requiredAccesses $requiredApplicationPermissions -permissionType "Role"
    }
    return $requiredAccess
}

Function ConfigureApplications
{
    if ([string]::IsNullOrWhiteSpace($AzureEnvironmentName))
    {
        $AzureEnvironmentName = "AzureCloud"
    }

    switch ($AzureEnvironmentName)
    {
        "AzureCloud" 
        {
            $url = "https://login.microsoftonline.com"; 
            $connectionUri = "https://outlook.office365.com/powershell-liveid/"; 
            $exchangeEnvName = "O365Default";
            break
        }
        "AzureChinaCloud"
        {
            $url = "https://login.chinacloudapi.cn"; 
            $connectionUri = "https://partner.outlook.cn/PowerShell"; 
            $exchangeEnvName = "O365China";
            break
        }
        "AzureUSGovernment"
        {
            $url = "https://login.microsoftonline.us"; 
            $connectionUri = "https://outlook.office365.us/powershell-liveid"; 
            $exchangeEnvName = "O365USGovGCCHigh";
            break
        }
        default 
        {
            throw "[$AzureEnvironmentName] was not found in the availbale list of azure environments"
        }
    }

    try
    {
        if ([string]::IsNullOrWhiteSpace($Credential) -and [string]::IsNullOrWhiteSpace($TenantId))
        {
            $creds = Connect-AzureAD -AzureEnvironmentName $AzureEnvironmentName
        }
        elseif ([string]::IsNullOrWhiteSpace($Credential) -and ![string]::IsNullOrWhiteSpace($TenantId))
        {
            $creds = Connect-AzureAD -TenantId $TenantId -AzureEnvironmentName $AzureEnvironmentName
        }
        elseif (![string]::IsNullOrWhiteSpace($Credential))
        {
            $creds = Connect-AzureAD -Credential $Credential -AzureEnvironmentName $AzureEnvironmentName
        }
        else
        {
            $creds = Connect-AzureAD -TenantId $TenantId -Credential $Credential -AzureEnvironmentName $AzureEnvironmentName
        }
    }
    catch [System.Exception]
    {
        Write-Error $PSItem.ToString()
        throw "Could not get credentials"
    }

    if ([string]::IsNullOrWhiteSpace($TenantId))
    {
        $TenantId = $creds.Tenant.Id
    }

    $tenant = Get-AzureADTenantDetail
    $tenantName =  ($tenant.VerifiedDomains | Where { $_._Default -eq $True }).Name

    # Get the user running the script
    $user = Get-AzureADUser -ObjectId $creds.Account.Id

    $isAppExists = Get-AzureADApplication -Filter "DisplayName eq 'Microsoft Identity Manager Service Mailbox client'"

    if ($isAppExists)
    {
        throw "Application 'Microsoft Identity Manager Service Mailbox client' already exists. Please delete it before creating a new one."
    }

    # Create the service AAD application
    Write-Host "Creating the AAD application (Microsoft Identity Manager Service Mailbox client)"
    # Get a 2 years application key for the service Application
    $pw = ComputePassword
    $fromDate = [DateTime]::Now;
    $key = CreateAppKey -fromDate $fromDate -durationInYears 2 -pw $pw
    $serviceAppKey = $pw
    
    # Create application with Redirect URl to Office365 Admin Portal
    $serviceAadApplication = New-AzureADApplication -DisplayName "Microsoft Identity Manager Service Mailbox client" `
                                                    -ReplyUrls "https://admin.microsoft.com/AdminPortal/" `
                                                    -PasswordCredentials $key `
                                                    -Oauth2AllowImplicitFlow $true `

    # add the user running the script as an app owner if needed
    $owner = Get-AzureADApplicationOwner -ObjectId $serviceAadApplication.ObjectId
    if ($owner -eq $null)
    { 
        Add-AzureADApplicationOwner -ObjectId $serviceAadApplication.ObjectId -RefObjectId $user.ObjectId
        Write-Host "'$($user.UserPrincipalName)' added as an application owner to app '$($serviceAadApplication.DisplayName)'"
    }

    $requiredResourcesAccess = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.RequiredResourceAccess]
 
    $requiredPermissions = GetRequiredPermissions -applicationDisplayName "Office 365 Exchange Online" `
                                                  -requiredApplicationPermissions "full_access_as_app" `

    $requiredResourcesAccess.Add($requiredPermissions)

    Set-AzureADApplication -ObjectId $serviceAadApplication.ObjectId -RequiredResourceAccess $requiredResourcesAccess

    # create mail-enabled security group and add user to this group
    Write-Host "Connecting to Exchange Online"
    Connect-ExchangeOnline -Credential $Credential -ConnectionUri $connectionUri -ExchangeEnvironmentName $exchangeEnvName
    
    Write-Host "Looking for MIMMailboxAccess"
    $group = Get-DistributionGroup -Identity "MIMMailboxAccess" -ErrorAction "SilentlyContinue" #Do not throw an error as group will be created further if it was not found
    
    if (!$group)
    {
        Write-Host "MIMMailboxAccess was not found. Creating it" 
        $group = New-DistributionGroup -Type Security -Name "MIMMailboxAccess"
    }
    
    Write-Host "Group found: " $group

    $distributionGroupMemberEmail = $MailboxAccountEmail
    if(!$distributionGroupMemberEmail)
    {
        $distributionGroupMemberEmail = $user.UserPrincipalName
    }
    
    Write-Host "Looking for distribution group member with email" $distributionGroupMemberEmail

    $mimMailBoxGroupMembers = Get-DistributionGroupMember -Identity "MIMMailboxAccess"
    
    $mimMailBoxGroupMemberExists = $False
    foreach($mimMailBoxGroupMember in $mimMailBoxGroupMembers)
    {
        if($mimMailBoxGroupMember.PrimarySmtpAddress -eq $distributionGroupMemberEmail)
        {
            $mimMailBoxGroupMemberExists = $True
            break
        }
    }
    
    if($mimMailBoxGroupMemberExists -eq $False)
    {
        Write-Host "Distribution group member was not found. Adding it" 
        Add-DistributionGroupMember -Identity "MIMMailboxAccess" -Member $distributionGroupMemberEmail -BypassSecurityGroupManagerCheck
    }
    else
    {
        Write-Host "Distribution group member with email" $distributionGroupMemberEmail "already exists"
    }

    
    Write-Host "Creating new access policy for the group"
    # add restrict policy for this group
    $groupName = "MIMMailboxAccess@" + $tenantName;
    New-ApplicationAccessPolicy -AccessRight RestrictAccess -AppId $serviceAadApplication.AppId -PolicyScopeGroupId $groupName -Description "Restrict access to application."
    
    Write-Host "Checking if user $distributionGroupMemberEmail has access to the current application"
    $testResult = Test-ApplicationAccessPolicy -Identity $distributionGroupMemberEmail -AppId $serviceAadApplication.AppId
    
    if ($testResult.AccessCheckResult -eq "Granted")
    {
        Write-Host "Access is granted"
    }
    else 
    {
        Write-Error $testResult.AccessCheckResult
    }
    
    $consentURL = "$url/$TenantId/adminconsent?client_id=$($serviceAadApplication.AppId)"

    Write-Host "`nWaiting 30 seconds until replication in Azure is done"
    Start-Sleep -Seconds 30

    Write-Host "Starting browser to accept permissions for the application"
    Start-Process -FilePath $consentURL

    Write-Warning "If you get an error in a browser then try this link a bit later: $consentURL"

    Write-Host "`n****************************************************************"
    Write-Host "ApplicationId: "  $serviceAadApplication.AppId
    Write-Host "TenantId: "  $TenantId
    Write-Host "ClientSecret: "  $serviceAppKey
    Write-Host "****************************************************************"
    Write-Host "Please copy client secret as it won't be saved"
}

# Pre-requisites
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Write-Host "Enabled TLS 1.2"

# Adding current user folder with modules as all modules will be installed in CurrentUser scope
$currentUserPath= $env:USERPROFILE + "\Documents\WindowsPowerShell\Modules"
$currentUserPathFiler = "*" + $currentUserPath + "*";
if ($env:PSModulePath -notlike $currentUserPathFiler)
{
    Write-Host "Adding " $currentUserPath " to PSModulePath"
    $env:PSModulePath = $env:PSModulePath + ";" + $currentUserPath
}

# Installing required modules. Check if these (or newer) modules has been installed before
if ((Get-InstalledModule -Name "PowerShellGet" -MinimumVersion 2.2.5 -ErrorAction SilentlyContinue) -eq $null)
{
    Write-Host "Installing PowerShellGet 2.2.5 as it was not found in the gallery"
    Install-Module PowerShellGet -Scope CurrentUser -RequiredVersion 2.2.5 -AllowClobber
}
if ((Get-InstalledModule -Name "AzureAD" -MinimumVersion 2.0.2.118 -ErrorAction SilentlyContinue) -eq $null)
{ 
    Write-Host "Installing AzureAD 2.0.2.118 as it was not found in the gallery"
    Install-Module -Name AzureAD -Scope CurrentUser -RequiredVersion 2.0.2.118 -AllowClobber
}
if ((Get-InstalledModule -Name "ExchangeOnlineManagement" -MinimumVersion 2.0.3 -ErrorAction SilentlyContinue) -eq $null) 
{ 
    Write-Host "Installing ExchangeOnlineManagement 2.0.3 as it was not found in the gallery"
    Install-Module -Name ExchangeOnlineManagement -Scope CurrentUser  -RequiredVersion 2.0.3 -AllowClobber
}
Import-Module PowerShellGet
Import-Module AzureAD
Import-Module ExchangeOnlineManagement

# Run interactively (will ask for the tenant ID and credentials if they are null)
ConfigureApplications -Credential $Credential -tenantId $TenantId -AzureEnvironmentName $AzureEnvironmentName -MailboxAccountEmail $MailboxAccountEmail

 

 

@IDM1999 

Yes, Microsoft actually updated their documentation a couple of days after my post and after I have had some interaction with Microsoft support team.

They provide a cmdlet on their documentation now (I assume your script is similar)

https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-...