Forum Discussion

manish1614's avatar
manish1614
Brass Contributor
Jul 19, 2022
Solved

Authentication Failure for IMAP and POP3 using Client Credential flow for OAuth2.0 | Java

I am facing an authentication failure issue while trying to connect for both IMAP and POP3 protocols using the Client Credential Grant flow for OAuth2.0

Where, I have been following the steps suggested in "https://docs.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth#get-an-access-token"

 

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

https://github.com/Azure-Samples/ms-identity-msal-java-samples/tree/main/1.%20Server-Side%20Scenarios/msal-client-credential-secret

 

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.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);	
			
			if(store.isConnected()){
				System.out.println("Connection Established using imap protocol successfully !");		
			}
		} catch (NoSuchProviderException e) {	// session.getStore()
			e.printStackTrace();
		} catch (MessagingException e) {		// store.connect()
			e.printStackTrace();
		}
	}

 

 

Java code for POP3:

 

 

public static void connectPOP(String email, String accessToken){
		Properties properties= new Properties();

        properties.put("mail.pop3.port", 995);
        properties.put("mail.pop3.forgettopheaders", "true");	

        properties.put("mail.pop3.auth.mechanisms", "XOAUTH2");
        properties.put("mail.pop3.auth.login.disable", "true");		// If true, prevents use of the USER and PASS commands. Default is false.
        properties.put("mail.pop3.auth.plain.disable", "true");		// If true, prevents use of the AUTH PLAIN command. Default is false.
        properties.put("mail.pop3.auth.xoauth2.disable","false");	// If true, prevents use of the AUTHENTICATE XOAUTH2 command. Hence set it to false
        properties.put("mail.pop3.auth.xoauth2.two.line.authentication.format", "true");  // If true, splits authentication command on two lines. Default is false.
       
        properties.put("mail.pop3.connectiontimeout", 15000);
        properties.put("mail.pop3.timeout", 15000);
        properties.put("mail.debug", "true");

        Session session = Session.getInstance(properties);
        session.setDebug(true);
        try{
	        Store store = session.getStore("pop3");
	        store.connect("outlook.office365.com", email, accessToken);
        
	        if(store.isConnected()){
	        	System.out.println("Connected with pop3 successfully !");
	        }
        }catch(Exception e){
        	e.printStackTrace();
        }
	}

 

 

 

Following are the credentials which I have used while performing the Client Credential Grant flow

  • userEmail:- Email of the user which is used to login to Azure portal (eg, email address removed for privacy reasons)
  •  authority=https://login.microsoftonline.com/<tenant - id - here>/
  •  client_id= <client(application) - id - here> 

  • secret= <client - secret - key - here>
  • scope= https://outlook.office.com/.default
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

 

Below Image contains list of permissions I have applied in my app:

Error Logs:

Spoiler

*** 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. [UABOADMAU...<token_value>]
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=email address removed for privacy reasons, 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 dXNlc...<token-value-here>
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)


*** POP3 ***

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,pop3,com.sun.mail.pop3.POP3Store,Oracle]
DEBUG POP3: mail.pop3.rsetbeforequit: false
DEBUG POP3: mail.pop3.disabletop: false
DEBUG POP3: mail.pop3.forgettopheaders: true
DEBUG POP3: mail.pop3.cachewriteto: false
DEBUG POP3: mail.pop3.filecache.enable: false
DEBUG POP3: mail.pop3.keepmessagecontent: false
DEBUG POP3: mail.pop3.starttls.enable: true
DEBUG POP3: mail.pop3.starttls.required: true
DEBUG POP3: mail.pop3.finalizecleanclose: false
DEBUG POP3: mail.pop3.apop.enable: false
DEBUG POP3: mail.pop3.disablecapa: false
DEBUG POP3: connecting to host "outlook.office365.com", port 995, isSSL false
javax.mail.AuthenticationFailedException: Read timed out
at com.sun.mail.pop3.POP3Store.protocolConnect(POP3Store.java:213)
at javax.mail.Service.connect(Service.java:366)
at javax.mail.Service.connect(Service.java:246)
at test.ClientCredentialGrantAndConnect.connectPOP(ClientCredentialGrantAndConnect.java:209)
at test.ClientCredentialGrantAndConnect.main(ClientCredentialGrantAndConnect.java:50)

 

Following is the list of jars I have used as a part of this development:

 

My Java Code Link(ideone): https://ideone.com/2RaWN9 

 

Please help and let me know if the program is not correct.

Or if any important step seems to be missing.

 

Thank you.

 

  • Hi. I had the same problem, but I think I made some progress.

     

    I read documentation few times, tried few times from the start with same error. I even have tried using client and object ids instead of email as username, in lack of better ideas.


    So this is where I think I have made mistake previous times.

     

    When you are at the part that you need to register service principal, you need to execute

     

    New-ServicePrincipal -AppId <APPLICATION_ID> -ServiceId <OBJECT_ID> [-Organization <ORGANIZATION_ID>]

     

     here I put enterprise application object id as ServiceId argument. And that is ok.

     

    But on 

     

    Add-MailboxPermission -Identity "email address removed for privacy reasons" -User 
    <SERVICE_PRINCIPAL_ID> -AccessRights FullAccess

     

    I have put my registered application object id as User argument. I also tried setting object id of enterprise application, but it did not have success.

    I also tried New-ServicePrincipal but with registered app object id as service id, but it gave me the same result.

     

    When I executed 

     

    Get-ServicePrincipal -Organization <ORGANIZATION_ID> | fl

     

     

    I did not pay attention to ServiceId property, even with documentation specifying it and saying it will be different.

     

    Now I cleared everything and started fresh.

    I executed all the steps again, but on the step when I need to add mail permission, I list service principals, and then use `ServiceId` value from the output, as argument for user.

     

    With that, I was able to authorise. 

     

    Unfortunately, now I receive `C3 BAD User is authenticated but not connected.` when I try to list inbox. But it is step forward.

     

    I am not sure if you made the same error as me, but maybe it will help you in some way.

    I will post info, when I find fix for the new error if somebody comes across same issue.  

60 Replies

  • DominikJasek's avatar
    DominikJasek
    Copper Contributor

    manish1614 first of all, thanks for your post - it helps me a lot (especially I'm not JAVA developer at all :cool:)

     

    Secondly, I would like to return the favor. You looked for the answer about POP3 issue, that it still not authenticate.

     

    If everything is set correctly, you just have to switch to POP3S.

           properties.put("mail.pop3s.port", "995");
    
            properties.put("mail.pop3s.ssl.enable", "false");
            properties.put("mail.pop3s.starttls.enable", "true");
            properties.put("mail.pop3s.starttls.required", "true");
    
            properties.put("mail.pop3s.connectiontimeout", 5000);
            properties.put("mail.pop3s.timeout", 5000);
            properties.put("mail.pop3s.partialfetch", false);
            properties.put("mail.pop3s.auth.mechanisms", "XOAUTH2");
    
            properties.put("mail.pop3s.forgettopheaders", "true");
            properties.put("mail.pop3s.sasl.enable", "true");
            properties.put("mail.pop3s.sasl.mechanisms", "XOAUTH2");
            properties.put("mail.pop3s.auth.login.disable", "true");
            properties.put("mail.pop3s.auth.plain.disable", "true");

     

    DEBUG: JavaMail version 1.6.2
    DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
    DEBUG: setDebug: JavaMail version 1.6.2
    DEBUG: getProvider() returning javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle]
    DEBUG POP3: mail.pop3s.rsetbeforequit: false
    DEBUG POP3: mail.pop3s.disabletop: false
    DEBUG POP3: mail.pop3s.forgettopheaders: true
    DEBUG POP3: mail.pop3s.cachewriteto: false
    DEBUG POP3: mail.pop3s.filecache.enable: false
    DEBUG POP3: mail.pop3s.keepmessagecontent: false
    DEBUG POP3: mail.pop3s.starttls.enable: true
    DEBUG POP3: mail.pop3s.starttls.required: true
    DEBUG POP3: mail.pop3s.finalizecleanclose: false
    DEBUG POP3: mail.pop3s.apop.enable: false
    DEBUG POP3: mail.pop3s.disablecapa: false
    DEBUG POP3: connecting to host "outlook.office365.com", port 995, isSSL true
    +OK The Microsoft Exchange POP3 service is ready.

     

    Unfortunately it's failing then on something else, but at least we were authenticated... :lol:

    DEBUG POP3: STLS required but not supported
    QUIT
    +OK Microsoft Exchange Server POP3 server signing off.
    javax.mail.AuthenticationFailedException: STLS required but not supported

     

    But that's another reason to switch to IMAP, and stop using POP3 - pardon POP3S

    • manish1614's avatar
      manish1614
      Brass Contributor
      Just thanks is not enough, so I'd like to express my heartfelt gratitude for all the effort you put into taking my work one step forward. You did a truly excellent and remarkable work, and I feel fortunate to have someone like you as a collaborator.

      Its a very appreciative work you did there by trying to resolve the POP3 related authentication problem. I appreciate your willingness to go above and beyond to help many people out there to achieve their goals.
  • Stpehan_WEGENER's avatar
    Stpehan_WEGENER
    Copper Contributor

    manish1614 

    I had exactly the same problem ; altought i followed the documentation of microsoft.

     

    I have finaly solved it :

    when i get request the oauth token, we should put "https://outlook.office365.com/.default" in the scope parameter

    but, since it is an uri, it should be encoded (in c# i use UrlEncode)

     

    after that, i was able to use the token in my sasl auth  message and then i was authenticated (and got the respons "+OK User successfully authenticated.")

    • manish1614's avatar
      manish1614
      Brass Contributor
      great to hear that your problem got solved.
      Thanks for pointing the UrlEncode trick in C# while assigning the scope param
  • crisanchile's avatar
    crisanchile
    Copper Contributor

    manish1614 

    This video explains the necessary steps to solve the problem, pay attention to the PowerShell commands

    https://www.youtube.com/watch?v=bMYA-146dmM&t=356s


     

    • shrey_soni's avatar
      shrey_soni
      Copper Contributor
      I have not implemented OAuth2.0 still my services works fine. So do I still need to work on implementing OAuth2.0? I am bit confused please help.
      • jambo's avatar
        jambo
        Brass Contributor

        If you are still using plaintext IMAP/POP auth, yes you most certainly you do. Microsoft will randomly disable Basic authentication up until the 31st of December 2022. In the interim if Basic Authentication has been disabled on your tenant it can be re-enabled following the following steps. How to temporarily re-enable IMAP plaintext auth in Office 365. 

        1. Login as azure administrator
        2. Click link: https://aka.ms/PillarEXOBasicAuth
        3. Click Run Tests
        4. Select IMAP, click check box, click update
  • shrey_soni's avatar
    shrey_soni
    Copper Contributor
    Hello, I have a question.
    We have same code that you have posted, so right now we use application password to connect with outlook and fetch emails. will this stop from 1st oct, do we need to move to OAuth2.0.
    • manish1614's avatar
      manish1614
      Brass Contributor

      shrey_soni Yes your understanding is correct, from 1st Oct 2022, you will be required to move to OAuth2 in case you are still using Basic Authentication technique.
      Please refer to this post for more information about the announcement.
      https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/deprecation-of-basic-authentication-exchange-online

  • kdhulipalla's avatar
    kdhulipalla
    Copper Contributor
    Hi Manish,

    I am also having similar issue and spent significant amount of time in searching for proper solution. Can you provide the steps that you followed in setting up the app to resolve the issue. I really appreciate your help.
  • borist2's avatar
    borist2
    Copper Contributor

    Hi. I had the same problem, but I think I made some progress.

     

    I read documentation few times, tried few times from the start with same error. I even have tried using client and object ids instead of email as username, in lack of better ideas.


    So this is where I think I have made mistake previous times.

     

    When you are at the part that you need to register service principal, you need to execute

     

    New-ServicePrincipal -AppId <APPLICATION_ID> -ServiceId <OBJECT_ID> [-Organization <ORGANIZATION_ID>]

     

     here I put enterprise application object id as ServiceId argument. And that is ok.

     

    But on 

     

    Add-MailboxPermission -Identity "email address removed for privacy reasons" -User 
    <SERVICE_PRINCIPAL_ID> -AccessRights FullAccess

     

    I have put my registered application object id as User argument. I also tried setting object id of enterprise application, but it did not have success.

    I also tried New-ServicePrincipal but with registered app object id as service id, but it gave me the same result.

     

    When I executed 

     

    Get-ServicePrincipal -Organization <ORGANIZATION_ID> | fl

     

     

    I did not pay attention to ServiceId property, even with documentation specifying it and saying it will be different.

     

    Now I cleared everything and started fresh.

    I executed all the steps again, but on the step when I need to add mail permission, I list service principals, and then use `ServiceId` value from the output, as argument for user.

     

    With that, I was able to authorise. 

     

    Unfortunately, now I receive `C3 BAD User is authenticated but not connected.` when I try to list inbox. But it is step forward.

     

    I am not sure if you made the same error as me, but maybe it will help you in some way.

    I will post info, when I find fix for the new error if somebody comes across same issue.  

    • gary21's avatar
      gary21
      Copper Contributor

      I just got IMAP to work thanks to this thread.

      Be careful to pass the raw token to store.connect() though. The last mistake I did was to process the token as explained in https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth#sasl-xoauth2

      But the library already takes care of that.

      • borist2's avatar
        borist2
        Copper Contributor
        Yes. It was something that I messed up in my code. Thanks.
    • Anjitha170's avatar
      Anjitha170
      Copper Contributor
      This took me back to the documentation to register the service principal in exchange. I was using the registered app's objectId in the New-Service-Principal and Add-MailBox-Permission cmdlets. I changed that to AAD Enterprise Applications's objectId in both commands. With that i'm able to authenticate and read mail from INBOX. The documentation is very confusing in terms of service principal identifier. The documentation says service principal identifier in the Add-MailBox-Permissions is different from the previous one. In my case both are same, which is the Enterprise Application's ObjectId. Thanks a lot for pointing this out. I have been stuck on this for days, now everything is working smoothly 🙂
  • Andre_Castro's avatar
    Andre_Castro
    Copper Contributor
    All I wanted was to access a mailbox, did not know I was trying to build a nuclear submarine. Microsoft did a terrible job of replacing a trivial process with something incredibly complicated, with multiple steps, and next to none support
  • DestryHines's avatar
    DestryHines
    Copper Contributor

    I'm having the same issue as well. I've tried every combination of things the documentation provides. If anyone finds a solution, please post it here.

     

    Not sure if it helps you guys but I noticed the first post shows the scope as "https://outlook.office.com/.default" but in this https://docs.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth#use-client-credentials-grant-flow-to-authenticate-imap-and-pop-connections:~:text=https%3A//outlook.office365.com/.default it specifically says to use "https://outlook.office365.com/.default".

    • manish1614's avatar
      manish1614
      Brass Contributor
      DestryHines Thanks for your response, it was a typo which I have corrected now from "https://outlook.office.com/.default" to "https://outlook.office365.com/.default".
      I have cross-checked the documentation several times now, but I am still unable to resolve this problem.
  • Anjitha170's avatar
    Anjitha170
    Copper Contributor

    manish1614I'm also facing the same issue with IMAP OAuth Authentication with Client Credentials flow. I have followed Microsoft's documentation as you mentioned above. I have given IMAP.AccessAsApp, POP.AccessAsApp permissions, but the access_token is not working with those permissions. Did you find any solution for this?

    • manish1614's avatar
      manish1614
      Brass Contributor
      Thanks for you reply Anjitha. As of now I have not found any solution for this issue. I will update on the same thread as soon as I find out a working fix for this situation.

Resources