aspnetcore: Blazor WebAssembly Msal breaks when attempting AD B2C Password Reset user flow
Describe the bug
Blazor WebAssembly authentication (Microsoft.Authentication.WebAssembly.Msal) relies on a state query param passed to B2C user flows to keep track of the authentication process and successfully log users in when they’re redirected back into the app. Because Msal currently does not support B2C user flows as first-class entities (at least for flows other than sign in, like password reset), we rely on manually building a user flow url (see example below), part of which is the state query param. If this param is completely left out, the Msal library will throw an unhandled error complaining that no state param was found.
This is an issue because we want to be able to handle the Password Reset user flow, which by design throws an error back to the initiating app (AADB2C90118) and it becomes the app’s responsibility to trigger the password reset as a separate user flow. As mentioned above, this currently happens by manually building the flow url, which brings us back to the original issue of populating the state query param.
To Reproduce
Modify Pages/Authentication.razor to look similar to what I have below, which is designed to handle the AD B2C AADB2C90118 error for linking sign in user flow with the password reset user flow:
@page "/authentication/{action}"
@using Microsoft.Extensions.Configuration;
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager NavManager
@inject IConfiguration Configuration
<RemoteAuthenticatorView Action="@Action" />
@code {
[Parameter] public string Action { get; set; }
protected override void OnAfterRender(bool firstRender)
{
if (Action == "login-failed")
{
var uri = NavManager.ToAbsoluteUri(NavManager.Uri);
if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("message", out var _loginError))
{
// Indicates that user attempted to initiate password reset flow
if (_loginError.Single().Contains("AADB2C90118"))
{
var resetPasswordFlow = Configuration["AzureAdB2C:ResetPasswordUserFlow"];
var clientId = Configuration["AzureAdB2C:ClientId"];
var redirectUri = $"{NavManager.BaseUri}authentication/login-callback";
var userFlowBuilder = $@"https://ourtenant.b2clogin.com/ourtenant.onmicrosoft.com/oauth2/v2.0/authorize
?p={resetPasswordFlow}
&client_id={clientId}
&redirect_uri={redirectUri}
&nonce=defaultNonce
&scope=openid
&response_type=id_token
&prompt=login";
var userFlowUrl = String.Concat(userFlowBuilder.Where(c => !Char.IsWhiteSpace(c)));
NavManager.NavigateTo(userFlowUrl, forceLoad: true);
}
}
}
}
}
Exceptions (if any)
blazor.webassembly.js?v=6:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Unexpected error in authentication.: Hash does not contain state.
AuthError: Unexpected error in authentication.: Hash does not contain state.
at new t (http://localhost:5000/_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js?v=2:16:24631)
Further technical details
.NET Core SDK (reflecting any global.json):
Version: 3.1.300
Commit: b2475c1295
Runtime Environment:
OS Name: debian
OS Version: 10
OS Platform: Linux
RID: debian.10-x64
Base Path: /usr/share/dotnet/sdk/3.1.300/
Host (useful for support):
Version: 3.1.4
Commit: 0c2e69caa6
.NET Core SDKs installed:
3.1.300 [/usr/share/dotnet/sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.App 3.1.4 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.4 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
To install additional .NET Core runtimes or SDKs:
https://aka.ms/dotnet-download
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 15 (7 by maintainers)
@pheuter thanks for letting us know. We will update to the latest msal.js version on the next major release.
@pheuter Authentication.Msal contains the msal specific implementation for AAD and AAD B2C, and uses WebAssembly.Authentication which implements the fundamental authentication primitives in Blazor