Click here to Skip to main content
15,886,724 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,

So Im getting positive results of Oauth authentication if I manually select an account to use within my browser, but since I do not want to select an account, I need my oauth to utilise the account that Im trying to get access to.

Dim L as String ="theloginemailaddress"
Dim PW as string="thepassword"
' obviously L and PW are normally populated with real info.

Using client As HttpClient = New HttpClient()
               Dim request = New FormUrlEncodedContent(New Dictionary(Of String, String) From {
                   {"grant_type", "password"},
                   {"client_id", SMTPOAUTH2_CLIENT_ID},
                   {"client_secret", SMTPOAUTH2_CLIENT_SECRET},
                   {"username", L},
                   {"scope", "Mail.Write"},
           {"Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{L}:{PW}"))}
                   })
               request.Headers.Add("X-PrettyPrint", "1")

               Dim response = client.PostAsync(SMTPOAUTH2_AUTHORENDPOINT, request).Result
               jsonResponse = response.Content.ReadAsStringAsync().Result



The json response returned, is an account selection page as I have several Outlook accounts. I figure its probably a parameter I can pass, that bypasses this and goes direct to the account. If anyone knows what the extra parameter is, I would be most grateful, I just cannot find the information I am looking for or may be using the wrong terminology in locating the information.

What I have tried:

as per the above code, I tried adding
{"Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{L}:{PW}"))}

which does not seem to do anything (and is probably wrong anyway) its something I lifted from a web page, but I just cannot get it to go to the account that I need and it may be just a parameter change - Im guessing.
Posted
Updated 6-Dec-22 4:56am

Rather than reinventing the wheel, use the Microsoft Authentication Library to get your OAuth2 tokens:
Learn about MSAL - Microsoft Entra | Microsoft Learn[^]

In this case, it looks like you want to use the "Username/password (ROPC)" flow:
Authentication flow support in the Microsoft Authentication Library (MSAL) - Microsoft Entra | Microsoft Learn[^]

NB: This flow is not really considered "secure". The client credentials flow is usually a better choice.

Once you have your token, you'll need an SMTP library which supports using SASL with an OAuth2 token to authenticate. Microsoft's recommended library is MailKit:
GitHub - jstedfast/MailKit: A cross-platform .NET library for IMAP, POP3, and SMTP.[^]
 
Share this answer
 
Comments
Member 12561559 6-Dec-22 7:25am    
Hi Richard, thanks for that - Ive managed to get it onto a test project for v4.8 winforms vb.net but I dont necessarily need all the email part of it - just the essential parameters I should be passing, without having an account selection - if I do the account selection i.e. click on it, then Im in and I get a json authtoken string, I guess I could save it and just reuse it until it expires, but I'd rather would be able to refresh it everytime it connects, so I dont have to do something about updating it every X days. I would rather not go the way of credentials as in the login and password either, Im just throwing it "out there" to see what I can replace that with. Thanks though and if you are able to just let me know what I need to get this auth token using the libraries that come with .net 4.6/4.8 that would be perfect.
Richard Deeming 6-Dec-22 7:35am    
I've used the MSAL and MimeKit libraries in an application that reads the email via IMAP, using both the ROPC and client credentials flows. It's fairly simple:
// Get an OAuth2 token using ROPC flow:
IPublicClientApplication app = PublicClientApplicationBuilder.Create(clientId).WithAuthority(AzureCloudInstance.AzurePublic, tenantId).Build();
AuthenticationResult authResult = await application.AcquireTokenByUsernamePassword(new[] { "https://outlook.office365.com/IMAP.AccessAsUser.All" }, username, password).ExecuteAsync();

// Or:

// Get an OAuth2 token using client credentials flow:
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(clientId).WithTenantId(tenantId).WithClientSecret(clientSecret).Build();
AuthenticationResult authResult = await application.AcquireTokenForClient(new[] { "https://outlook.office365.com/.default" }).ExecuteAsync();

(Depending on the type of application you're building, you may need to cache the application in the ROPC version, and check for a cached token.)

Once you have the token, using it with MailKit is simple:
await client.AuthenticateAsync(new SaslMechanismOAuth2(mailboxYouWantToAccess, authenticationResult.AccessToken));

If you don't want to use MailKit, they you're going to need to read and understand how SASL and XOAUTH2 work:
Authenticate an IMAP, POP or SMTP connection using OAuth | Microsoft Learn[^]
Member 12561559 6-Dec-22 10:55am    
That was a nightmare but I figured it out - your code helped find the vb.net equivalent - so I will post this as the solution, people can then just re-use it to get the authtoken, then use whatever email component they use, passing the json authtoken as needed. Thanks Richard - took me a while (all day) but got there in the end - or seems it, I have managed to get the authtoken, I just have to pop it into my main sub's that performs outgoing mail using the Chilkat Software component which will just (supposed) to use the Authtoken json string and do its magic. Cheers
Member 12561559 12-Dec-22 8:25am    
Managed to do testing with mailkit to, using the authentication saslmechanismoauth2 statement above, so im definitely getting a auth token back successfully, just an issue with permissions to send email - so I think thats at the Office365 Outlook end. Thanks Richard - you were most helpful - top fella
So thanks to Richard, his code got me searching and I managed to find what I needed, to acquire the AuthToken, without using a browser, just replace the values with your own and pass the AuthToken string to your mail component to mail onwards using OAuth2

Public Function GetAccessToken() As String
    Dim tenantId = "aa9....."
    Dim clientId = "1fb...."
    Dim authorityUri As String = "https://login.microsoftonline.com/........./oauth2/v2.0/authorize"
    Dim redirectUri = "http://localhost:3017"
    Dim scopes = New List(Of String) From {
        "put your scope in here"
    }
    Dim clientSecret = "bUn....."
    Dim confidentialClient = ConfidentialClientApplicationBuilder.Create(clientId).WithClientSecret(clientSecret).WithAuthority(New Uri(authorityUri)).WithRedirectUri(redirectUri).Build()
    Dim accessTokenRequest = confidentialClient.AcquireTokenForClient(scopes)
    Dim accessToken = accessTokenRequest.ExecuteAsync().Result.AccessToken
    Return accessToken
End Function
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900