Blazorade / Blazorade-MSAL

A Blazor component library that makes it easy to use authentication in your application through MSAL, both in Blazor Server and Blazor WebAssembly applications.
MIT License
17 stars 5 forks source link

Problem with LoginRedirectHandler component #27

Open mr-nuno opened 2 years ago

mr-nuno commented 2 years ago

net6 v2.1.0 and 2.2.0 of BlazoradeMsal

Expected authentication flow:

  1. Checks token in MainLayout with AcquireTokenAsync
  2. If no token present gets redirected to Azure
  3. Logins in and gets redirected to https://localhost:5001/signin-redirect
  4. If OnLoginSucceeded navigate to startpage
  5. If OnLoginFailed show error

I'm using the LoginRedirectHandler component on my redirect uri in my application. In my case https://localhost:5001/signin-redirect. When I add the LoginRedirectHandler to that page i seems to process the redirect data from Azure AD but it doesn't get the OnLoginSucceeded or the OnLoginFailed event. It just process the query data from the provider and stops. Without errors. image The login is succesful because I have all the token information in my local storage.

If I try to use the HandleRedirectPromiseAsync in my signin-redirect page it doesnt seem to process the provider data from the redirect. image Or sometimes end up in a redirect loop with a error message saying that you couldnt be logged in. image

// MainLayout.razor

...

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        await _msalService.AcquireTokenAsync(fallbackToDefaultLoginHint: true)
    }

    await base.OnAfterRenderAsync(firstRender);
}

...
// SignedIn.razor

@page "/signin-redirect"

@layout MainLayout

@inject NavigationManager _navigationManager;

<LoginRedirectHandler 
    OnLoginSucceeded="@LoginSucceeded" // also tried with this.LoginSucceeded
    OnLoginfailed="@LoginFailed"> // also tried with this.LoginFailed
</LoginRedirectHandler>

@if(null != _exception)
{
    <pre>@_exception.ToString()</pre>
}

@code {
    private Exception? _exception;
    private void LoginSucceeded(AuthenticationResult token)
    {
        _navigationManager.NavigateTo("/");
    }

    private void LoginFailed(Exception ex)
    {
        _exception = ex;
        StateHasChanged();
    }
}
mr-nuno commented 2 years ago

Now I get the following

System.ArgumentNullException: Value cannot be null. (Parameter 'module')
   at Blazorade.Core.Interop.DotNetInstanceCallbackHandler`2[[Blazorade.Msal.Security.AuthenticationResult, Blazorade.Msal, Version=2.2.0.0, Culture=neutral, PublicKeyToken=null],[System.Object, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]..ctor(IJSObjectReference module, String functionIdentifier, Dictionary`2 data)
   at Blazorade.Core.Interop.DotNetInstanceCallbackHandler`1[[Blazorade.Msal.Security.AuthenticationResult, Blazorade.Msal, Version=2.2.0.0, Culture=neutral, PublicKeyToken=null]]..ctor(IJSObjectReference module, String functionIdentifier, Dictionary`2 data)
   at Blazorade.Msal.Services.BlazoradeMsalService.AcquireTokenSilentAsync(TokenAcquisitionRequest request)
   at Blazorade.Msal.Services.BlazoradeMsalService.AcquireTokenAsync(TokenAcquisitionRequest request)
   at Blazorade.Msal.Services.BlazoradeMsalService.AcquireTokenAsync(String loginHint, IEnumerable`1 scopes, Boolean fallbackToDefaultLoginHint, Nullable`1 prompt)

This is when I try to call AcquireTokenAsync

MikaBerglund commented 2 years ago

Thanks for reporting! I'll start looking into this.

Just a few initial questions:

  1. Do you get the same error / problem when trying to run the BlazorWasmSample application?
  2. Do you still get the problem if you try to switch the interactive login mode from InteractiveLoginMode.Redirect to InteractiveLoginMode.Popup?
mr-nuno commented 2 years ago

Thanks for reporting! I'll start looking into this.

Just a few initial questions:

  1. Do you get the same error / problem when trying to run the BlazorWasmSample application?
  2. Do you still get the problem if you try to switch the interactive login mode from InteractiveLoginMode.Redirect to InteractiveLoginMode.Popup?

No error. The wasm example is working fine Yes, popup works just fine but in that case you never land on the redirect page.

mr-nuno commented 2 years ago

If I skip the LoginRedirectHandler component I got it work with this solution.

This in MainLayout

var loginHint = await _msalService.GetDefaultLoginHintAsync();
if (string.IsNullOrEmpty(loginHint))
{
   await _msalService.AcquireTokenAsync();
}
else
{
    await _msalService.AcquireTokenAsync(loginHint: loginHint);
}

And changed redirect uri in Azure app to / and skipped the separate SignedIn view.

But it feels like you could end up in a redirect loop with this solution. If AcquireTokenAsync cant find a cached token it will send you on a endless login loop.

MikaBerglund commented 2 years ago

I remember having similar issues when I was working on the sample applications. I just can't remember what those issues exactly were.

I'll see if I can repro your problem with your original setup. Blazorade MSAL should definitely work with both server and WASM applications, and both redirect and popup interaction modes. Personally, I prefer the popup mode, because the user does not lose the context as easily as might happen when redirecting back and forth. Still, redirecting is fully supported in MSAL, so it should be fully supported also in Blazorade MSAL.

I'll look into this.