Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wait for 'AuthenticationContext.AcquireTokenAsync()' synchronouslly?

First of all, I'm not sure if this is important, but for the reasons mentioned by @Simon Mourier in him answer, I'm using the EXPERIMENTAL build of ADAL, this one.


In the code below, I would like to retrieve an AuthenticationResult synchronouslly, so, I will wait for completition of the authentication by AcquireTokenAsync method in a synchronous manner.

This is because a boolean flag should be set after the authorization is done (isAuthorized = true), but tgis need to happen in a synchronous way, because if not, then I can call other methods of the class that will throw a null reference because the call to AcquireTokenAsync didn't finished so the object is null.

The following code does not work, the method will never return, because the call to AcquireTokenAsync method seems that indefinitely freezes the thread.

C# (maybe wrong syntax due to online translation):

public void Authorize() {
    // Use the 'Microsoft.Experimental.IdentityModel.Clients.ActiveDirectory' Nuget package for auth.
    this.authContext = new AuthenticationContext(this.authUrl, this.cache);
    this.authResult = this.authContext.AcquireTokenAsync({ "https://outlook.office.com/mail.readwrite" }, 
                                                         null, this.clientIdB, this.redirectUriB, 
                                                         new PlatformParameters(PromptBehavior.Auto, this.windowHandleB)).Result;

    // Use the 'Microsoft.Office365.OutlookServices-V2.0' Nuget package from now on.
    this.client = new OutlookServicesClient(new Uri("https://outlook.office.com/api/v2.0"), () => Task.FromResult(this.authResult.Token));
    this.isAuthorizedB = true;
}

VB.NET:

Public Sub Authorize()

    ' Use the 'Microsoft.Experimental.IdentityModel.Clients.ActiveDirectory' Nuget package for auth.
    Me.authContext = New AuthenticationContext(Me.authUrl, Me.cache)

    Me.authResult =
        Me.authContext.AcquireTokenAsync({"https://outlook.office.com/mail.readwrite"}, 
                                         Nothing, Me.clientIdB, Me.redirectUriB,
                                         New PlatformParameters(PromptBehavior.Auto, Me.windowHandleB)).Result

    ' Use the 'Microsoft.Office365.OutlookServices-V2.0' Nuget package from now on.
    Me.client = New OutlookServicesClient(New Uri("https://outlook.office.com/api/v2.0"),
                                           Function() Task.FromResult(Me.authResult.Token))

    Me.isAuthorizedB = True

End Sub

I researched a little bit and I tried other two alternatives, but happens the same..

1st:

ConfiguredTaskAwaitable<AuthenticationResult> t = this.authContext.AcquireTokenAsync(scopeUrls.ToArray(), null, this.clientIdB, this.redirectUriB, new PlatformParameters(PromptBehavior.Auto, this.windowHandleB)).ConfigureAwait(false);

this.authResult = t.GetAwaiter.GetResult();

2nd:

this.authResult == RunSync(() => { return this.authContext.AcquireTokenAsync(scopeUrls.ToArray(), null, this.clientIdB, this.redirectUriB, new PlatformParameters(PromptBehavior.Auto, this.windowHandleB)); })

private AuthenticationResult RunSync<AuthenticationResult>(Func<Task<AuthenticationResult>> func)
{
    return Task.Run(func).Result;
}
like image 263
ElektroStudios Avatar asked May 21 '16 19:05

ElektroStudios


2 Answers

How to wait for 'AuthenticationContext.AcquireTokenAsync()' synchronouslly?

I suspect this issue is caused by calling the async method in the UI thread. Currently, my workaround is wrapping the call a new work thread.

    private void button1_Click(object sender, EventArgs e)
    {
        Authorize().Wait();
    }

    private Task Authorize()
    {
        return Task.Run(async () => {
            var authContext = new AuthenticationContext("https://login.microsoftonline.com/common");

            var authResult = await authContext.AcquireTokenAsync
            (new string[] { "https://outlook.office.com/mail.readwrite" },
             null,
             "{client_id}",
             new Uri("urn:ietf:wg:oauth:2.0:oob"),
             new PlatformParameters(PromptBehavior.Auto, null));
        });
    }
like image 56
Jeffrey Chen Avatar answered Oct 19 '22 00:10

Jeffrey Chen


I fought this problem for 2 days on Xamarin.Android. It just never returns from the AquireTokenAsync method. The answer is almost comical. You need to add the following in your MainActivity.cs:

    protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
    {
        base.OnActivityResult(requestCode, resultCode, data);
        AuthenticationAgentContinuationHelper.SetAuthenticationAgentContinuationEventArgs(requestCode, resultCode, data);
    }

Funny thing is, it actually says ContinuationHelper... smh.

like image 5
Kasper Avatar answered Oct 18 '22 22:10

Kasper