Search code examples
javaoauth-2.0office365imap

Microsoft exchange - IMAP OAuth2 With client credentials


I am writing application that need to read mailbox using IMAP, but as daemon, without user interaction. I need to use OAuth2 to get access. Because I need it without user interaction, I need to use client credentials flow. This was added this June.

I have done everything from official documentation. Registered application, added permissions, added mailbox permission using PowerShell.

When I get request access token with scope https://outlook.office365.com/.default, the one that I receive has role IMAP.AccessAsApp, so I believe that is correct. I used https://jwt.ms/ to parse JWT.

The problem is when I try to authenticate using this access token in Java, for example

    Properties props = new Properties();
    props.put("mail.imap.ssl.enable", "true");
    props.put("mail.imap.auth.mechanisms", "XOAUTH2");
    props.put("mail.debug", "true");

    Session session = Session.getInstance(props);
    Store store = session.getStore("imap");
    store.connect("outlook.office365.com", 993, "[email protected]", "accessToken");

I receive AUTHENTICATE failed. I tried same code with access token received using authorization code flow, which requires user interaction. Using that access code I was able to connect to mailbox. So the code is correct.

I even tried using client id and service id instead of email address as username, but without success.

I am not sure where I made the mistake and if I am using correct username. Any help is appreciated.


Solution

  • I wrote same answer here, so I am coping it here.

    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.

    On the part where it is needed to register service principal, I needed to execute

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

    Here I have 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.

    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 have executed all the steps again, but on the step for creating new service principal I used data from enterprise application view. 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.