aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

[Blazor Wasm AD B2C] Authentication OnLogInSucceeded event fired multiple times.

Open andersson09 opened this issue 2 years ago • 7 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Describe the bug

There seems to be a few related issues:

  1. By default the same token network request with scope: openid profile offline_access, grant_type: refresh_token is being called twice (is this necessary?). The authentication response time is already quite slow so this is pretty painful.
  2. By default the OnLogInSucceeded event in RemoteAuthenticatorView is firing twice.
  3. Passing [CascadingParameter] public Task<AuthenticationState>? AuthenticationState { get; set; } causes OnLogInSucceeded to fire three times. Is there a better way of retrieving the user claims here?
  4. For application insights we need to set the AuthenticatedUserContext. By calling SetAuthenticatedUserContext the OnLoginSucceeded is being called four times!

Full code:

<RemoteAuthenticatorView Action="@Action" OnLogInSucceeded="OnLogInSucceeded" OnLogOutSucceeded="OnLogOutSucceeded" >
    <LogInFailed>
        <ErrorDisplay Title="Sorry, your login failed." RetryText="logging in again" RetryAction="RedirectToLogin" 
            OnError="@(() => LogError("LogInFailed"))" />
    </LogInFailed>
    <LogOutFailed>
        <ErrorDisplay Title="Sorry, log out operation failed." RetryText="refreshing the page" RetryAction="RefreshPage" 
            OnError="@(() => LogError("LogOutFailed"))" />
    </LogOutFailed>
</RemoteAuthenticatorView>

@code{

    [Parameter] public string? Action { get; set; }
    [CascadingParameter] public Task<AuthenticationState>? AuthenticationState { get; set; }

    private async Task OnLogInSucceeded()
    {
        Console.WriteLine("onlogin");
        var user = (await AuthenticationState!).User;
        await AppInsights.SetAuthenticatedUserContext(user.Id(), storeInCookie: true);
    }

    private async Task OnLogOutSucceeded()
    {
        Console.WriteLine("onlogout");
        await AppInsights.ClearAuthenticatedUserContext();
    }

Expected Behavior

  1. scope: openid profile offline_access, grant_type: refresh_token token network request to be called once
  2. OnLoginSucceeded to only be called once

Steps To Reproduce

Blazor WebAssembly standalone with Azure AD B2C

Exceptions (if any)

No response

.NET Version

6.0.101

Anything else?

No response

andersson09 avatar Feb 12 '22 13:02 andersson09

Thanks for contacting us.

We're moving this issue to the .NET 7 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

ghost avatar Feb 14 '22 17:02 ghost

This needs to be fixed sooner than .NET 7 planning stage. We are having this exact same issue. .NET 6.0.2 using Azure AD B2C. OnLoginSucceeded fires multiple times, which means that some post-login work we want to do can happen multiple times. It should happen just once and be dependable to fire only once, especially if we need to do any long running tasks during login like downloading some information from a Web API after the user has authenticated successfully.

Right now, I have to check the nonce value that comes back on the AdditionalProperties dictionary of the RemoteUserAccount and compare it to previous calls to know if I have done work before.

Lastly, shouldn't OnLoginSucceeded complete before the application tries to initialize a destination page it is trying to navigate to?

stephajn avatar Mar 07 '22 23:03 stephajn

I know the title of this says AD B2C but I am having the same issue with normal AAD Authentication and OnLoginSucceded, except for me it fires constantly, forever, over and over again.

I am using Blazor WASM Hosted and OnLoginSucceded (on the Client) I am simply calling an API on the Server.

This is the Authentication.razor file

@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

<RemoteAuthenticatorView Action="@Action" OnLogInSucceeded="GetCurrentUserProfile"/>

This is the code behind. Authentication.razor.cs file

    public partial class Authentication
    {
        [Inject] public IUserProfileService UserProfileService { get; set; }
        [Inject] public CurrentUserProfileState CurrentUserProfileState { get; set; }
        [Parameter] public string? Action { get; set; }


        private async Task GetCurrentUserProfile()
        {
            CurrentUserProfileState.UserProfileState = await UserProfileService.RetrieveCurrentUserProfileAsync();
        }
    }

CurrentUserProfileState Is a singleton to store the result of the API call.

But when trying to login, I am stuck on a page that looks like this image

And when I inspect the Brwoser Console, it is constantly call the Server API over and over again forever until I kill the process. image

Am I doing some stupidly wrong here? This is the approach everyone tells me to use to do Post Login activities, so I'd thought they would have ran inito this as well.

Gareth064 avatar Apr 14 '22 14:04 Gareth064

@Gareth064 found a solution? Same problem here. As soon as i try to await it hangs.

Without the "await Task.Delay(1);" it works fine.

image

image

wrkntwrkn avatar May 26 '22 14:05 wrkntwrkn

@wrkntwrkn Nope, didn't find a solution that would work so I abandoned the feature in my app until this is sorted.

Gareth064 avatar May 27 '22 08:05 Gareth064

Fires twice with AAD B2C for me, .NET 6

johnbaro avatar Aug 10 '22 23:08 johnbaro

Even if this issue won't be fixed for .NET 7, the least Microsoft could do is provide some guidance on a workaround or recommended best practice to mitigate this issue. A list of do's and don'ts even? Or an alternative way to do post-login work if there is one?

Anything would be helpful for this rather than leaving us out to dry on this because this can't possibly be an edge use case for most developers.

stephajn avatar Aug 11 '22 15:08 stephajn

I agree with the above comments. At the least, some guidance on how to avoid this issue would be helpful.

dev-jlb avatar Aug 25 '22 13:08 dev-jlb

If it helps anyone, personally, using fluxor I just fire off an action when OnLoginSucceeded fires and when handling that action, I check current state to see if I've already fired it (it triggers a logged in bool) and ignore subsequent events.
Could be done using a static variable or local storage or some such as well.
Pretty simple but it works.

johnbaro avatar Aug 26 '22 00:08 johnbaro

Duplicate of https://github.com/dotnet/aspnetcore/issues/39507

danroth27 avatar Sep 07 '22 16:09 danroth27

Does the other ticket include fix for:

  1. By default the same token network request with scope: openid profile offline_access, grant_type: refresh_token is being called twice (is this necessary)?

andersson09 avatar Sep 07 '22 16:09 andersson09