Ogglas
Ogglas

Reputation: 69928

Azure AD Service Principal client credentials grant AUTHENTICATE failed accessing outlook.office365.com mailbox via IMAP

I have followed these two guides on how to use client credentials grant flow to authenticate IMAP.

https://learn.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

https://www.limilabs.com/blog/oauth2-client-credential-flow-office365-exchange-imap-pop3-smtp

The app registration has the following permissions:

enter image description here

I have successfully given my application's service principal access to the mailbox I wish to read:

enter image description here

The obtained access token looks good with roles matching what I want to do:

enter image description here

I have used both Microsoft.Identity.Client and System.Net.Http.HttpClient to get a token successfully and I have used both MailKit.Net.Imap.ImapClient and Limilabs.Client.IMAP.Imap to connect with the token but no client has worked. What could the error be?

public async Task GetEmailAsync(CancellationToken cancellationToken = default)
{
    var clientId = "";
    var tenantId = "";
    var clientSecret = "";
    var outlookDomain = "outlook.office365.com";
    var email = "";

    var app = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithTenantId(tenantId)
    .WithClientSecret(clientSecret)
    .Build();

    string[] scopes = new string[] {
    "https://outlook.office365.com/.default"
};

    var result = await app.AcquireTokenForClient(scopes)
.ExecuteAsync();

    string accessToken = result.AccessToken;

    using (Imap client2 = new Imap())
    {
        client2.ConnectSSL(outlookDomain);
        client2.LoginOAUTH2(email, accessToken);
        client2.SelectInbox();

        client2.Close();
    }

    var adb2cTokenResponse = GetAccessTokenAsync(clientId, clientSecret).GetAwaiter().GetResult();

    var oauth2Test = new SaslMechanismOAuth2(email, accessToken);
    var client = new ImapClient();
    await client.ConnectAsync(outlookDomain, 993, SecureSocketOptions.Auto, cancellationToken);
    await client.AuthenticateAsync(oauth2Test);
    await client.DisconnectAsync(true);
}

private async Task<Adb2cTokenResponse> GetAccessTokenAsync(string clientId, string clientSecret)
{
    var client = new HttpClient();

    var kvpList = new List<KeyValuePair<string, string>>();
    kvpList.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
    kvpList.Add(new KeyValuePair<string, string>("client_id", clientId));
    kvpList.Add(new KeyValuePair<string, string>("scope", "https://outlook.office365.com/.default"));
    kvpList.Add(new KeyValuePair<string, string>("client_secret", clientSecret));

#pragma warning disable SecurityIntelliSenseCS // MS Security rules violation
    var req = new HttpRequestMessage(HttpMethod.Post, $"https://login.microsoftonline.com/<domain>.onmicrosoft.com/oauth2/v2.0/token")
    { Content = new FormUrlEncodedContent(kvpList) };
#pragma warning restore SecurityIntelliSenseCS // MS Security rules violation

    using var httpResponse = await client.SendAsync(req);

    var response = await httpResponse.Content.ReadAsStringAsync();

    httpResponse.EnsureSuccessStatusCode();

    var adb2cTokenResponse = JsonSerializer.Deserialize<Adb2cTokenResponse>(response);

    return adb2cTokenResponse;
}

enter image description here

enter image description here

Upvotes: 0

Views: 826

Answers (1)

Ogglas
Ogglas

Reputation: 69928

Turned out to be a global rule blocking IMAP, POP and SMTP protocols. After excluding the application service principal from this rule in AD it started working like expected.

SMTP with client credentials grant flow did not work though.

As per the current test with SMTP Oauth 2.0 client credential flow with non-interactive sign in is not supported.

https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth#smtp-protocol-exchange

Also verify that you use the correct SERVICE_PRINCIPAL_ID:

https://stackoverflow.com/a/73166725/3850405

Upvotes: 1

Related Questions