Navigating the Latest B2C Library Updates with Azure AD

Wednesday, May 15, 2019

Navigating the Latest B2C Library Updates with Azure AD

If you're anything like me, you typically go straight to the source when it comes to product documentation and, as a result, you may have set up your ASP.NET Core application using some sample code you found out of GitHub to show you how to integrate against Azure Active Directory B2C. By using this sample code, you'll end up with a project with the following artifacts:

  • NuGet package references for Microsoft.Identity.Client, Microsoft.AspNetCore.Authentication.Cookies and Microsoft.AspNetCore.Authentication.OpenIdConnect
  • A configuration class containing all possible settings you think you'll need to get B2C going - oftentimes too many
  • A class similar to OpenIdConnectOptionsSetup in the sample
  • A Session class to return your Challenge methods against the directory

This code hasn't really changed in some time. But if you just updated your libraries, you'll find that your dependencies did. I just updated these libraries in a project I've been working on since last fall and somehow managed to break everything. While my dependencies didn't seem to change, the dependencies of my dependencies did, creating breaking changes with exceptions pointing to this MSAL wiki page which seems to indicate that more breaking changes were ahead.

To be fair, this is a long time coming. I've been using this same code over a number of different projects over the past couple of years, making adjustments here and there as needed over the past couple of years, but all in all running with the same collection of code.

So what's the fix? Remove these packages and reference Microsoft.AspNetCore.Authentication.AzureADB2C.UI instead.

This handy little library very conveniently hides away lots of details, giving you a configuration object, an Account object for login/logout/profile tasks, and other conveniences to the point where all you do is add two lines of code:

    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent 
        //for non-essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
        .AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options));

Two Caveats

The scaffolding code in the JetBrains Rider project worked perfectly for some sample apps I tried out over the past couple of months (which is how I discovered this handy library). HOWEVER, today's library updates creates some breaking changes.

When migrating into the B2C UI library, I ran into this error when trying to authenticate:

HttpRequestException: Response status code does not indicate success: 404 (Not Found).

System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()

IOException: IDX20804: Unable to retrieve document from: '[PII is hidden]'.
Microsoft.IdentityModel.Protocols.HttpDocumentRetriever
    .GetDocumentAsync(string address, CancellationToken cancel)

InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII is hidden]'.
Microsoft.IdentityModel.Protocols.ConfigurationManager<T>
.GetConfigurationAsync(CancellationToken cancel)

If you're using the URL in the Instance property of this configuration file:

  "AzureAdB2C": {
    "Instance": "https://login.microsoftonline.com/tfp/",
    "ClientId": "11111111-1111-1111-11111111111111111",
    "CallbackPath": "/signin-oidc",
    "Domain": "yourtenant.onmicrosoft.com",
    "SignUpSignInPolicyId": "",
    "ResetPasswordPolicyId": "",
    "EditProfilePolicyId": ""
  },

Congratulations! Your authentication process is broken! Please go to all of your 3rd parties and replace it with https://login.microsoftonline.com/te/ because that's what's being used now.

However - if you're using the b2clogin.com domain provided some time back, you're in good shape - it still works. If you're not using b2clogin.com, now is a good time to update everything to use it instead of https://login.microsoftonline.com/te/.

Your appsettings.{Environment}.json should look something like this:

  "AzureAdB2C": {
    "Instance": "https://yourtenant.b2conline.com/",
    "ClientId": "11111111-1111-1111-11111111111111111",
    "CallbackPath": "/signin-oidc",
    "Domain": "yourtenant.onmicrosoft.com",
    "SignUpSignInPolicyId": "B2C_1_SUSI",
    "ResetPasswordPolicyId": "B2C_1_RP",
    "EditProfilePolicyId": "B2C_1_PE"
  },