Fabrice
Fabrice

Reputation: 931

Mailkit Can't authenticate with O365 oAuth2 account

I tried to authenticate on a O365 application I created on the Azure portal and it doesn't work as expected.

The following code works well but it's using a login/password and it's not recommended by Microsoft. (found here https://github.com/jstedfast/MailKit/issues/989)

var scopes = new[] { "https://outlook.office365.com/IMAP.AccessAsUser.All" };

var confidentialClientApplication = PublicClientApplicationBuilder.Create(_clientId).WithAuthority(AadAuthorityAudience.AzureAdMultipleOrgs).Build();

SecureString securePassword = new NetworkCredential("", _userPassword).SecurePassword;
var acquireTokenByUsernamePasswordParameterBuilder = confidentialClientApplication.AcquireTokenByUsernamePassword(scopes, _userMail, securePassword);
var authenticationResult = acquireTokenByUsernamePasswordParameterBuilder.ExecuteAsync().Result;

if (_debugCall)
{
imapClient = new ImapClient(new ProtocolLogger(_configurationId + "_IMAP_" + DateTime.Now.ToString("yyyyMMddHHssffff") + ".log"));
}
else
{
imapClient = new ImapClient();
}
        
imapClient.CheckCertificateRevocation = false;
imapClient.ServerCertificateValidationCallback = (s, c, h, e) => true;

imapClient.Connect(_webServiceUrl, _webServicePort, SecureSocketOptions.Auto);
imapClient.Authenticate(new SaslMechanismOAuth2(_userMail, authenticationResult.AccessToken));  

if (string.IsNullOrEmpty(_folder))
{
oFolder = imapClient.Inbox;
}    
else
{
oFolder = imapClient.GetFolder(_folder);
}
oFolder.Open(FolderAccess.ReadWrite);

In fact I want to be able to authenticate using the tenanid, client secret and clientid but without the interactive mode (as the app is a windows services).

So I tried to use another code with the tenantid, clientSecret and ClientId but I receive the "Authentication failed" error message :

  var confidentialClientApplication = ConfidentialClientApplicationBuilder
    .Create(_clientId)
    .WithClientSecret(_clientSecret)
    .WithRedirectUri("http://localhost")
    .WithAuthority(new Uri("https://login.microsoftonline.com/" + _tenantid + "/"))
    .Build();
             
    var scopes = new[] { "https://outlook.office365.com/.default" };
    
    var authenticationResult = confidentialClientApplication.AcquireTokenForClient(scopes);
            
    var authToken = authenticationResult.ExecuteAsync().Result;
    var oauth2 = new SaslMechanismOAuth2(_userMail, authToken.AccessToken);
    imapClient = new ImapClient(new ProtocolLogger("TEST_IMAP_" + DateTime.Now.ToString("yyyyMMddHHssffff") + ".log"));
    
    imapClient.CheckCertificateRevocation = false;
    imapClient.ServerCertificateValidationCallback = (s, c, h, e) => true;
               
    imapClient.Connect(_webServiceUrl, _webServicePort, SecureSocketOptions.Auto);
    imapClient.Authenticate(oauth2);

I've the following permission for my app on the Azure portal:

MSGraph
IMAP.AccessAsUser.All
Mail.Read
Mail.ReadWrite
Mail.Send

Did I miss something? I'm afraid it may be impossible? The official sample on Mailkit website use the interactive mode.

Btw, I'm using Mailkit v2.4

Thank you for your help.

Upvotes: 5

Views: 3822

Answers (1)

jstedfast
jstedfast

Reputation: 38528

It appears that OAUTH2 authentication with Office365 via the non-interactive method is unsupported by the Microsoft Exchange IMAP/POP3/SMTP protocols and that the only way to get access to Office365 mail using the non-interactive method of OAUTH2 authentication is via the Microsoft.Graph API.

I've been getting a lot of questions about this over the past few months and as far as I'm aware, no one (myself included) has been able to find a way to make this work.

I keep hoping to see someone trying to do this (even in another language) here on StackOverflow with an accepted answer. So far, all I've seen are questions about OAuth2 using the interactive approach (which, as you've seen, I have written documentation for and is known to work well with MailKit).

Upvotes: 4

Related Questions