javaoauth-2.0exchange-serverimappop3

Authentication Failure for IMAP using Client Credential flow for OAuth2.0 | Java | Exchange Online


I am facing an authentication failure issue while trying to connect for both IMAP protocols using the Client Credential Grant flow for OAuth2.0. Where, I have been following the steps suggested by Microsoft in its step-by-step guide i.e. "Authenticate an IMAP, POP or SMTP connection using OAuth"

I have been using this github project to fetch the Access Token using Client Credential Grant flow: MSAL Client Credential Grant using Java

Java Code for IMAP

public static void connectIMAP(String userEmail, String accessToken){
    String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
    Properties props= new Properties();
    
    props.put("mail.imap.ssl.enable", "true");
    props.put("mail.imap.sasl.enable", "true");
    props.put("mail.imap.port", "993");
    
    props.put("mail.imap.auth.mechanisms", "XOAUTH2");
    props.put("mail.imap.sasl.mechanisms", "XOAUTH2");
    
    props.put("mail.imap.auth.login.disable", "true");
    props.put("mail.imap.auth.plain.disable", "true");
    
    props.setProperty("mail.imap.socketFactory.class", SSL_FACTORY);
    props.setProperty("mail.imap.socketFactory.fallback", "false");
    props.setProperty("mail.imap.socketFactory.port", "993");
    props.setProperty("mail.imap.starttls.enable", "true");
    
    props.put("mail.debug", "true");
    props.put("mail.debug.auth", "true");

    Session session = Session.getInstance(props);
    session.setDebug(true);

    try {
        final Store store = session.getStore("imap");                   
        store.connect("outlook.office365.com",userEmail, accessToken);  
        
    } catch (NoSuchProviderException e) {   // session.getStore()
        e.printStackTrace();
    } catch (MessagingException e) {        // store.connect()
        e.printStackTrace();
    }
}

Following are the credentials I have used while performing the Client Credential Grant flow using MSAL library

[Note: I have been using the Default Active Directory, and the default user(Admin) for my Azure account. Is it fine this way ? or does it require a new custom Azure AD and a separate tenant for performing client credential flow]

Following image contains list of permissions I have applied in my app: IMAGE for list of permissions applied

Error Logs:

    *** IMAP *** 

DEBUG: JavaMail version 1.5.6
DEBUG: successfully loaded resource: /META-INF/javamail.default.providers
DEBUG: Tables of loaded providers
DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], com.sun.mail.smtp.SMTPTransport=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle], com.sun.mail.imap.IMAPSSLStore=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], com.sun.mail.pop3.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], com.sun.mail.imap.IMAPStore=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle]}
DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], smtps=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]}
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: setDebug: JavaMail version 1.5.6
DEBUG: getProvider() returning javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle]
DEBUG IMAP: mail.imap.fetchsize: 16384
DEBUG IMAP: mail.imap.ignorebodystructuresize: false
DEBUG IMAP: mail.imap.statuscachetimeout: 1000
DEBUG IMAP: mail.imap.appendbuffersize: -1
DEBUG IMAP: mail.imap.minidletime: 10
DEBUG IMAP: enable STARTTLS
DEBUG IMAP: enable SASL
DEBUG IMAP: SASL mechanisms allowed: XOAUTH2
DEBUG IMAP: closeFoldersOnStoreFailure
DEBUG IMAP: trying to connect to host "outlook.office365.com", port 993, isSSL true
* OK The Microsoft Exchange IMAP4 service is ready. [UABO......]
A0 CAPABILITY
* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=XOAUTH2 SASL-IR UIDPLUS ID UNSELECT CHILDREN IDLE NAMESPACE LITERAL+
A0 OK CAPABILITY completed.
DEBUG IMAP: AUTH: PLAIN
DEBUG IMAP: AUTH: XOAUTH2
DEBUG IMAP: protocolConnect login, host=outlook.office365.com, user=ManishPrajapati@SampleOrg2022.onmicrosoft.com, password=<non-null>
DEBUG IMAP: SASL Mechanisms:
DEBUG IMAP:  XOAUTH2
DEBUG IMAP: 
DEBUG IMAP: SASL client XOAUTH2
DEBUG IMAP: SASL callback length: 2
DEBUG IMAP: SASL callback 0: javax.security.auth.callback.NameCallback@73f9ac
DEBUG IMAP: SASL callback 1: javax.security.auth.callback.PasswordCallback@1064425
A1 AUTHENTICATE XOAUTH2 dXNlcj.....
A1 NO AUTHENTICATE failed.
javax.mail.AuthenticationFailedException: AUTHENTICATE failed.
    at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:725)
    at javax.mail.Service.connect(Service.java:366)
    at javax.mail.Service.connect(Service.java:246)
    at test.ClientCredentialGrantAndConnect.connectIMAP(ClientCredentialGrantAndConnect.java:166)
    at test.ClientCredentialGrantAndConnect.main(ClientCredentialGrantAndConnect.java:45)

Any help in figuring out the issue will be highly appreciated.

Thank you.


Solution

  • I am now able to perform the OAuth2.0 authentication for IMAP protocol on exchange-online server. I found the issue with my approach was that, I was using some parameters from wrong places due to lack of experience on working with Azure.

    Following the instructions given in step by step guide and setting permissions of newly created application was OK. But the real problem was with the queries given at the end of this post where we need to run 3 commands in order to make it possible to perform OAuth2.0

    As per my understanding, following is the list of parameters used while performing Service Principal related queries:

    Parameters used (and where to find them):

    Commands:

    1. New-ServicePrincipal -AppId appId -ServiceId entObjId -Organization orgId
    2. Get-ServicePrincipal -Organization entObjId | fl
    3. Add-MailboxPermission -Identity "<email_id_here>" -User entObjId -AccessRights FullAccess

    Confusions I faced: