javax.mail.AuthenticationFailedException: AUTHENTICATE failed.

2023-03-31T12:05:43.7766667+00:00

Hello @Shweta Mathur ,
Here is my code Java :

private static final String AUTHORITY = "https://login.microsoftonline.com/%s/oauth2/v2.0/token";
    private static final String GRANT_TYPE = "client_credentials";
    private static final String RESOURCE = "https://outlook.office365.com/.default";
    final static String clientId = "myClientId";
     final static String clientSecret = "myClientSecret";
     final static String tenantId = "myTenantId";
    private final String username;
    private final String accessToken;

    public EmailClient(String username, String accessToken) {
        this.username = username;
        this.accessToken = accessToken;
    }

    public void connect() throws Exception {
        String host = "outlook.office365.com";
        String protocol = "imaps";
        int port = 993;

        Properties properties = new Properties();
        properties.put("mail.imaps.host", host);
        properties.put("mail.imaps.port", port);
        properties.put("mail.imaps.starttls.enable", "true");
        properties.put("mail.imaps.auth.login.disable", "true");
        properties.put("mail.imaps.auth.plain.disable", "true");
        properties.put("mail.imaps.sasl.enable", "true");
        properties.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
        properties.put("mail.imap.sasl.oauth2.scope", RESOURCE);
        properties.put("mail.imaps.sasl.authorizationid", username);
        properties.put("mail.imaps.sasl.oauth2.access.token", accessToken);

        Session session = Session.getInstance(properties);
        IMAPStore store = (IMAPStore) session.getStore(protocol);
        
        store.connect(host, port, username, accessToken);
       
        Folder inbox = store.getFolder("inbox");
        inbox.open(Folder.READ_ONLY);

      Message[] messages = inbox.getMessages();
      for (Message message : messages) {
        File file = new File("email-" + message.getSubject() + ".eml");
        try (FileOutputStream fos = new FileOutputStream(file)) {
          message.writeTo(fos);
        }
      }

      inbox.close();
      store.close();
    }
    public static String getAccessToken() throws IOException {
        String authority = String.format(AUTHORITY, tenantId);
        String encodedCredentials = Base64.getEncoder().encodeToString((clientId + ":" + clientSecret).getBytes());

        URL url = new URL(authority);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Authorization", "Basic " + encodedCredentials);
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

        Map<String, String> params = new HashMap<>();
        params.put("grant_type", GRANT_TYPE);
        params.put("scope", RESOURCE);
        String postData = getPostData(params);

        conn.setDoOutput(true);
        conn.getOutputStream().write(postData.getBytes());

        String response = "";
        Scanner scanner = new Scanner(conn.getInputStream());
        while (scanner.hasNext()) {
            response += scanner.nextLine();
        }
        scanner.close();

        String accessToken = response.substring(response.indexOf("\"access_token\":\"") + 16);
        accessToken = accessToken.substring(0, accessToken.indexOf("\""));
        System.out.println(accessToken);
        return accessToken;
    }

    private static String getPostData(Map<String, String> params) throws IOException {
        StringBuilder postData = new StringBuilder();
        for (Map.Entry<String, String> param : params.entrySet()) {
            if (postData.length() != 0) {
                postData.append('&');
            }
            postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
            postData.append('=');
            postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
        }
        return postData.toString();
    }

I am facing issue while try to access the microsoft mailbox using the access token and oAuth2.

With this implementation i get my acces token with all permission that i have added with my application Azure Microsoft.
I am using the javamail to connect, but getting the below error.

Exception in thread "main" javax.mail.AuthenticationFailedException: AUTHENTICATE failed.
	at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:732)
	at javax.mail.Service.connect(Service.java:366)
	at routines.Email.main(Email.java:54)
Microsoft Exchange Online
Microsoft Entra ID
Microsoft Entra ID
A Microsoft Entra identity service that provides identity management and access control capabilities. Replaces Azure Active Directory.
21,804 questions
{count} votes

Accepted answer
  1. Shweta Mathur 29,751 Reputation points Microsoft Employee
    2023-04-04T12:15:02.8433333+00:00

    Hi @javax.mail.AuthenticationFailedException , Thanks for updating the question in detail. As per the above code, you are using IMAP OAuth protocol with client credential flow to get the access token. You are not able to authenticate successfully as the service principal has not been registered successfully. For client credentials flow, you need to add application permissions under Office 365 Exchange Online image.png

    Make sure to grant admin consent for all the application permissions. Once consent has been provided, the admin must register your AAD application's service principal in Exchange using powerShell by following commands: Install ExchangeOnlineManagement Install-Module -Name ExchangeOnlineManagement -allowprerelease Import-module ExchangeOnlineManagement Connect-ExchangeOnline -Organization Register Service Principal in Exchange: 1.New-ServicePrincipal -AppId <APPLICATION_ID> -ServiceId <OBJECT_ID> [-Organization <ORGANIZATION_ID>] Make sure to use ObjectId from enterprise applications rather than object id of application registration.
    For the same application you registered in Application Registration. A corresponding application has been created in Enterprise Application as well. You need to pass object id from there while registering service principal in Exchange: enter image description here

    2.Get-ServicePrincipal | fl 3.Add-MailboxPermission -Identity "john.smith@contoso.com" -User <SERVICE_PRINCIPAL_ID> -AccessRights FullAccess In the application, you need to use scope = 'https://outlook.office365.com/.default ' Once you get the access token, you can create and open a Java Mail connection to read mails.

    Properties props = new Properties();
    
    props.put("mail.store.protocol", "imap");
    props.put("mail.imap.host", "outlook.office365.com");
    props.put("mail.imap.port", "993");
    props.put("mail.imap.ssl.enable", "true");
    props.put("mail.imap.starttls.enable", "true");
    props.put("mail.imap.auth", "true");
    props.put("mail.imap.auth.mechanisms", "XOAUTH2");
    props.put("mail.imap.user", mailAddress);
    props.put("mail.debug", "true");
    props.put("mail.debug.auth", "true");
    
    // open mailbox....
    String token = getAuthToken(tanantId,clientId,client_secret);
    Session session = Session.getInstance(props);
    session.setDebug(true);
    Store store = session.getStore("imap");
    store.connect("outlook.office365.com", mailAddress, token);
    
    

    Hope this will help. Thanks, Shweta Please remember to "Accept Answer" if answer helped you.

    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.