3

I'm trying to acquire a token using MSAL.NET and am pretty much using their tutorial code out of the box.

using Microsoft.Identity.Client;
using MyApp.Interfaces;
using System;
using System.Threading.Tasks;

namespace MyApp.NetworkServices
{
    public class MyAuthorizationClient : IMyAuthorizationClient
    {
        private readonly string[] _resourceIds;
        private IConfidentialClientApplication App;

        public MyAuthorizationClient(IMyAuthenticationConfig MyAuthenticationConfig)
        {
            _resourceIds = new string[] { MyAuthenticationConfig.MyApimResourceID };

            App = ConfidentialClientApplicationBuilder.Create(MyAuthenticationConfig.MyApimClientID)
                .WithClientSecret(MyAuthenticationConfig.MyApimClientSecret)
                .WithAuthority(new Uri(MyAuthenticationConfig.Authority))
                .Build();
        }

        public async Task<AuthenticationResult> GetMyAccessTokenResultAsync()
        {
            AuthenticationResult result = null;

            try
            {
                result = await App.AcquireTokenForClient(_resourceIds).ExecuteAsync().ConfigureAwait(continueOnCapturedContext:false);
            }
            catch(MsalClientException ex)
            {
                ...
            }
            return result;            
    }
}

}

The issue I'm having is that in the await call, it never returns. The debugger doesn't resume control and the application comes to the foreground as if it continued running. Im unable to interrogate the results of result, and I've already configured the await to not continue.

I reviewed this great thread but it am not getting any solutions for my scenario: Async call with await in HttpClient never returns

8protons
  • 3,591
  • 5
  • 32
  • 67
  • I'm struggling with the exact same issue. I was able to use WithLogging() on the ApplicationBuilder and output to a file to get some logging at least but it always dies on "Fetching instance discovery from the network from host login.microsoftonline.com." Haven't been able to figure out what the actual underlying cause is but maybe that will help you diagnose your issue further. – Chartreugz Dec 09 '20 at 15:03
  • I was able to get it to throw an exception instead of crashing the debugger by using .ExecuteAsync().Result without the await, this caused it to actually evaluate and give me something back. Seems my scopes are wrong, not sure why though. – Chartreugz Dec 09 '20 at 15:22

2 Answers2

3

Your code:

try
{
    result = await App.AcquireTokenForClient(_resourceIds).ExecuteAsync().ConfigureAwait(continueOnCapturedContext:false);
}

Remove the await and use .Result instead of .ConfigureAwait():

try
{
    result = App.AcquireTokenForClient(_resourceIds).ExecuteAsync().Result;
}

When I did this, the debugger actually caught an exception instead of closing abruptly. For my situation, turns out my scopes (aka _resourceIds in your code) were wrong. The scope that actually worked for my use case:

private string[] Scopes = new[]
{
    "https://graph.microsoft.com/.default"
};
Chartreugz
  • 293
  • 1
  • 10
  • 2
    "Remove the async and use .Result instead of .ConfigureAwait():" - that is terrible, terrible advice, IMO – Marc Gravell Dec 09 '20 at 15:33
  • 1
    @MarcGravell That's a really useless comment. Please feel free to contribute a solution which works. I understand that .Result is a bad practice for this, but this solved my problem and might solve the OPs problem. Should I revert my code to a state where nothing works just to follow best practices? I'd love it if ExecuteAsync worked without having to tack on ConfigureAwait or using the Result, but it simply doesn't in the example code given by Microsoft themselves. – Chartreugz Dec 09 '20 at 15:41
  • Your code worked, but so too did the original when I added a general `Exception` catch block. The exception was exactly like yours, too. Thank you – 8protons Dec 09 '20 at 17:31
  • @8protons Glad it worked out for you! Unfortunately, in my case there was no exception being thrown at all, the debugger terminated itself without any errors when the line was run. – Chartreugz Dec 09 '20 at 17:58
  • 1
    @MarcGravell @Chartreugz Using this example code https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth I was having the same issue even catching a general `Exception`. By calling `AcquireTokenForClient` in a separate `try` `catch` and removing the `await` and using `.Result`, this now works - nothing else was changed. – Kevin Swann Mar 10 '21 at 12:01
  • This solution worked for me too. I spent whole day, i wasn't getting any error the corde would return as soon as I get to the async call, no error nothing I could see. Replacing the code with the suggestion worked for me and I was able to send the email. – Jashvita Jan 19 '22 at 20:56
0

The problem is that I wasn't catching the general exception. The following allowed me to discover my issue, which is that I didn't have the correct scope:

public async Task<AuthenticationResult> GetMyAccessTokenResultAsync()
{
    AuthenticationResult result = null;

    try
    {
        result = await App.AcquireTokenForClient(_resourceIds).ExecuteAsync();
    }
    catch(MsalClientException ex)
    {
        ...
    }
    catch(Exception ex)
    {
        ...
    }

    return result;            
}
8protons
  • 3,591
  • 5
  • 32
  • 67
  • I had the try and catch just like yours but it did not catch any error. Just replacing the async with the result did work for me, no error found. – Jashvita Jan 19 '22 at 20:58