Search code examples
c#oauth-2.0mailkit

Authentication failed exception with MailKit OAuth2.0


I'm using the following code to get an access token and connect to the mail folder:

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

var scopes = new string[] { ".default" };

var authToken = await confidentialClientApplicationBuilder.AcquireTokenForClient(scopes).ExecuteAsync();

var oauth2 = new SaslMechanismOAuth2(username, authToken.AccessToken);

using (ImapClient client = new ImapClient())
{
    await client.ConnectAsync("outlook.office365.com", 993, SecureSocketOptions.SslOnConnect);
    await client.AuthenticateAsync(oauth2);

    //TODO

    await client.DisconnectAsync(true);
}

Everything seems to work correctly here, the ImapClient is connected and I can see oauth2.Credentials.Password is populated with the access token. However, when I run it the AuthenticateAsync method throws the error:

MailKit.Security.AuthenticationException: 'Authentication failed.'

I have noticed that the authToken.Account is null and that's why I'm passing the account name in by the string username. Also it seems I have to use the .default scope as anything else causes an error on AcquireTokenForClient as per this question.

Any ideas what I'm doing wrong here?


Solution

  • It seems that what you want is not possible at this time. See this Github issue for details.

    Basically, using ConfidentialClientApplicationBuilder can only use scopes defined as "API permissions" on your AppRegistration. If you have registered IMAP.AccessAsUser.All or Mail.Read Graph permissions, and requested them using the https://graph.microsoft.com/.default scope, you will get an access token, but it can only be used by the Graph API REST endpoints Microsoft has exposed.

    MailKit does not support these Graph API endpoints (as the linked issue describes).

    In order to use the IMAP support in MailKit it seems you must get an access token using PublicClientApplicationOptions as demonstrated in the MailKit example. This has the disadvantage of popping up the browser asking the user to authenticate themselves.

    It is, however, uncertain how long this will work, as it seems Microsoft will deprecate their IMAP endpoints (as mentioned in the previously linked issue)