I have a problem with accessing the Outlook mail inbox of a Microsoft account. It all begins with logging in, successfully, and getting an access token or a refresh token. Basically, when I call ConfidentialClientApplication.AcquireTokenByAuthorizationCodeAsync when logging into my Microsoft account, my app does not want to use the same authorization code twice, since it believes that that I am using an expired authorization code.
Here is my "OnTokenResponseReceived" function, where I am calling ConfidentialClientApplication.AcquireTokenByAuthorizationCodeAsync:
public async Task OnTokenResponseReceived(TokenResponseReceivedContext context) { _logger.LogInformation("in public async Task OnTokenResponseReceived(TokenResponseReceivedContext context)"); _logger.LogInformation("code = " + code); string userId = context.Ticket.Principal.FindFirst(ClaimTypes.NameIdentifier).Value; Microsoft.Identity.Client.TokenCache tokenCache = new SessionTokenCache(userId, context.HttpContext).GetMsalCacheInstance(); Microsoft.Identity.Client.ClientCredential clientCred = new Microsoft.Identity.Client.ClientCredential(_azuread.ClientSecret); ConfidentialClientApplication cca = new ConfidentialClientApplication(_azuread.ClientId, string.Format(CultureInfo.InvariantCulture, _azuread.AadInstance, _azuread.Tenant, "/v2.0"), _oauth2.RedirectUri, clientCred, tokenCache, null); try { Microsoft.Identity.Client.AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, _oauth2.AppScopes.Split(' ')); } catch { /* var ccaUsersGetEnumerator = cca.Users.GetEnumerator(); if (ccaUsersGetEnumerator.MoveNext()) { Microsoft.Identity.Client.AuthenticationResult result = await cca.AcquireTokenSilentAsync(_oauth2.AppScopes.Split(' '), ccaUsersGetEnumerator.Current); } */ throw; } finally { }; }
ConfidentialClientApplication.AcquireTokenByAuthorizationCodeAsync fails. Thus, the catch block is triggered, and the throw statement runs. Then, the event function "OnRemoteFailure" runs. Here is my implementation of "OnRemoteFailure":
private Task OnRemoteFailure(FailureContext context) { context.HandleResponse(); context.Response.Redirect("/Home/Error?message=" + context.Failure.Message); return Task.FromResult(0); }
My FailureContext.Failure.Message says the following:
"AADSTS70000: The provided value for the 'code' parameter is not valid. The code has expired.\r\nTrace ID: 8c9eac2b-d2dd-4a46-a53d-01ed43ba0300\r\nCorrelation ID: af04f562-9287-4d48-aaef-bab08bfa5b48\r\nTimestamp: 2017-08-03 05:55:30Z"
Whereas, if I am logging into my work or school account, my app believes that it should get an access token with the authorization code that was provided. Thus, ConfidentialClientApplication.AcquireTokenByAuthorizationCodeAsync succeeds. I am able to access the Outlook mail inbox of a work or school account.
In the case of logging in with my Microsoft account, I found out after researching online that instead of getting an access token, I have to get a refresh token, but the problem is that the ConfidentialClientApplication that I initialized does not believe that it has a user. I was thinking that I needed to store the refresh token in the cache for the specific user. (Notice that in the "catch" block of my "OnTokenResponseReceived" function, I commented out the part where I tried to get the refresh token, since I wanted to show you that I ran into the error of the expired authorization code, first. However, I could not get the refresh token since ConfidentialClientApplication.Users.Count is 0.) Here is a screenshot of the ConfidentialClientApplication.Users.Count being 0.
If I am using an expired authorization code in the first place, how would I get a refresh token?
Here is my GitHub repository.
Sorry for creating another discussion about a similar problem to the problem that I resolved, today. Thanks!