Register.Microsoft.Authentication.WebAssembly.Msal 6.0.2-rc1

This is a prerelease version of Register.Microsoft.Authentication.WebAssembly.Msal.
dotnet add package Register.Microsoft.Authentication.WebAssembly.Msal --version 6.0.2-rc1                
NuGet\Install-Package Register.Microsoft.Authentication.WebAssembly.Msal -Version 6.0.2-rc1                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Register.Microsoft.Authentication.WebAssembly.Msal" Version="6.0.2-rc1" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Register.Microsoft.Authentication.WebAssembly.Msal --version 6.0.2-rc1                
#r "nuget: Register.Microsoft.Authentication.WebAssembly.Msal, 6.0.2-rc1"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Register.Microsoft.Authentication.WebAssembly.Msal as a Cake Addin
#addin nuget:?package=Register.Microsoft.Authentication.WebAssembly.Msal&version=6.0.2-rc1&prerelease

// Install Register.Microsoft.Authentication.WebAssembly.Msal as a Cake Tool
#tool nuget:?package=Register.Microsoft.Authentication.WebAssembly.Msal&version=6.0.2-rc1&prerelease                

Modified Microsoft.Authentication.WebAssembly.Msal

Problem statement:

  • Creating a .NET 6 Blazor WASM project
  • Using Azure Active Directory B2C directory for authentication
  • Was unable to use Microsoft.Authentication.WebAssembly.Msal package to start Registration and Profile user flows

Caveat

This may be supported by MS, but I was unable to find a way to make it work...even after crawling through the source code. Of course, this doesn't mean it isn't support, it just means I couldn't find it.

Work-around

I forked the aspnetcore repo for .NET 6.0.2 on github to https://github.com/dougclutter/aspnetcore. Next, I created a SLNF file that included the Microsoft.Authentication.WebAssembly.Msal package and all it's dependencies (13 projects in all).

According to the B2C documentation, you start a user flow by inititiating a sign in with the authority set to the user flow. For example:

The Problem

There's no discernable way to specify the authority for the register/profile options. Microsoft allows you to configure B2C in the appsettings.json file as follows:

{
  "AzureAdB2C": {
    "Authority": "https://myB2C.b2clogin.com/myB2C.com/B2C_1_Signin",
    "ClientId": "be15af53-b152-43ee-8a61-42d48f06e44d",
    "ValidateAuthority": false
  }
}

This works great if you only want to use a single user flow, but it falls apart quickly if you want to use multiple user flows. They do allow you to add a local URL for register and profile using these settings:

{
  "AzureAdB2C": {
    "Authority": "https://myB2C.b2clogin.com/myB2C.com/B2C_1_Signin",
    "ClientId": "be15af53-b152-43ee-8a61-42d48f06e44d",
    "ValidateAuthority": false,
    "RemoteProfilePath": "/myLocalProfilePath",
    "RemoteRegisterPath": "/myLocalRegisterPath"
  }
}

But this doesn't really help us with all the complicated handshakes needed to authenticate against B2C, so I'm not sure what they were thinking when they added this.

So, after banging my head against this, I decided to just change things to solve the problem. Isn't open source fun?

My Horrible Hack

First, I had to find someplace to store the authorities in their settings. They already have an array called KnownAuthorities, so I just repurposed it for my needs:

{
  "AzureAdB2C": {
    "Authority": "https://myB2C.b2clogin.com/myB2C.com/B2C_1_Signin",
    "ClientId": "be15af53-b152-43ee-8a61-42d48f06e44d",
    "ValidateAuthority": false,
    "KnownAuthorities": [
      "https://myB2C.b2clogin.com/myB2C.com/B2C_1_Signin",
      "https://myB2C.b2clogin.com/myB2C.com/B2C_1_Signup",
      "https://myB2C.b2clogin.com/myB2C.com/B2C_1_Profile"
    ]
  }
}

Next, I had to modify their RemoteAuthenticatorViewCore to pass the authority that I wanted to use for each operation:

        protected override async Task OnParametersSetAsync()
        {
            switch (Action)
            {
                case RemoteAuthenticationActions.LogIn:
                    await ProcessLogIn(GetReturnUrl(state: null), 0);
                    break;
                case RemoteAuthenticationActions.LogInCallback:
                    await ProcessLogInCallback();
                    break;
                case RemoteAuthenticationActions.LogInFailed:
                    break;
                case RemoteAuthenticationActions.Profile:
                    await ProcessLogIn(GetReturnUrl(state: null), 2);
                    break;
                case RemoteAuthenticationActions.Register:
                    await ProcessLogIn(GetReturnUrl(state: null), 1);
                    break;
                case RemoteAuthenticationActions.LogOut:
                    await ProcessLogOut(GetReturnUrl(state: null, Navigation.ToAbsoluteUri(ApplicationPaths.LogOutSucceededPath).AbsoluteUri));
                    break;
                case RemoteAuthenticationActions.LogOutCallback:
                    await ProcessLogOutCallback();
                    break;
                case RemoteAuthenticationActions.LogOutFailed:
                    break;
                case RemoteAuthenticationActions.LogOutSucceeded:
                    break;
                default:
                    throw new InvalidOperationException($"Invalid action '{Action}'.");
            }
        }

Note that I'm just passing in the index of the authority I want to use for the corresponding operation. After that, it was pretty easy to modify the entire stack so it used the index.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
6.0.2-rc1 235 3/25/2022