1/5/2024 Admin

Creating A Blazor Server Azure B2C App (Updated to .NET 8)


image

You can authenticate the users in your Blazor application (and even manage your users) using Azure Active Directory B2C.

Also see: Creating A Blazor WebAssembly Azure B2C Application

 

Azure Active Directory B2C

Azure Active Directory B2C is a service that allows your Blazor website users to log in using their preferred social or enterprise logins (or they can create a new local account in your Azure B2C tenant). Because this is an Azure Active Directory tenant, you have access to powerful features such as Multi Factor Authentication and Conditional Access control.

You can get more details at the following links:

The pricing is really affordable, basically you get the first 50,000 users for free.

 

Set-Up An Azure Active Directory B2C Tenant

image

Creating an Azure Active Directory B2C Tenant requires an Azure Account.

Sign in to the Azure Portal using an existing account at: https://portal.azure.com/ or sign-up for a new one at: https://azure.microsoft.com/en-us/free/.

Note: An Azure account that's been assigned at least the Contributor role within the Azure subscription or a resource group within the subscription is required.

Follow the directions here: Tutorial - Create an Azure Active Directory B2C tenant | Microsoft Docs

 

image

In the Azure Portal, click Create a resource and search for Azure Active Directory B2C and press enter.

 

image

Click Create.

 

image

Click Create a new Azure AD B2C Tenant.

 

image

Fill out the form and click Review + Create.

Note: After you create the Azure B2C Tenant, you will need to link it to an Azure account for billing. To do this, follow the directions here: Billing model for Azure Active Directory B2C | Microsoft Docs

 

image

After the Azure B2C Tenant is set up, search for it and select it using the All resources.

 

image

This will direct you to a screen that will display a link to allow you to navigate to the tenant.

 

Register A Web Application

 

image

To allow the application, we will create later, to interact with Azure Active Directory B2C Tenant it must be registered.

Select App Registrations, then New registration.

 

image

Give the application a Name, Select Accounts in any identity provider or organizational directory, also Grant admin consent to openid and offline_access permissions, and click Register.

The App Registration will be created.

 

Configure Azure B2C Application Identity Provider & User Flow

In this example we will create a User Flow to allow login using a Microsoft Account using the directions here: Set up sign-up and sign-in with a Microsoft Account - Azure AD B2C | Microsoft Docs.

 

image

In the Azure B2C Tenant, click User flows then select New user flow.

 

image

Select Sign up and sign In.

 

image

Select Recommended for the Version and click Create.

 

image

Give the Flow a name and select None for Local accounts and Microsoft Account for Social Identity providers.

If you don’t see the Microsoft option see: Configure Microsoft as an identity provider.

 

image

Select options for Multifactor authentication.

 

image

For User attributes and token claims, select Show more…

 

image

Select the options in the image above.

Click Ok.

 

image

Finally, click Create.

 

image

The Flow will show in the User flows section.

Clicking on it will allow further configuration if needed.

 

Create The Blazor Server Azure B2C Application

image

Using Visual Studio 2022 (or higher) with .net8 (or higher) installed select Create a new project.

Select Blazor Web App.

 

image

Name the project BlazorAzureB2C and click Next.

 

image

Select .Net 8.0, Authentication type to none and click Create.

 

Add the Redirect URI in the Azure App Registration

image

In the Solution Explorer, open the launchSettings.json file in the Properties folder.

 

image

Copy the applicationUrl in the Profiles section, that begins with https.

 

image

In the Azure Portal, search for the App registration created earlier and select it.

 

image

Select Add a Redirect URI.

 

image

Select Add a platform.

 

image

Select Web.

 

image

Enter the URL of the Blazor application (copied earlier), with /signin-oidc at the end.

Check the Access and ID tokens boxes, and click the Configure button.

Note: When you deploy the application to a production website, you will need to add the URI of that address to this page.

 

Update the appsettings.json File

image

In Visual Studio, in the Solution Explorer, open the Appsettings.json file.

Replace all the contents with the following:

 

{
  /*
The following identity settings need to be configured
before the project can be successfully executed.
For more info see https://aka.ms/dotnet-template-ms-identity-platform 
*/
  "AzureAdB2C": {
    "Instance": "https://{Your Azure B2C Domain Name}.b2clogin.com/tfp/",
    "ClientId": "{Your Application (client) ID}",
    "CallbackPath": "/signin-oidc",
    "Domain": "{Your Azure B2C Domain Name}.onmicrosoft.com",
    "SignUpSignInPolicyId": "{Your Signup policy}",
    "ResetPasswordPolicyId": "",
    "EditProfilePolicyId": ""
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

 

The following values need to be replaced with values from your Azure B2C Tenant and App registration:

  • {Your Azure B2C Domain Name}
  • {Your Application (client) ID}
  • {Your Signup policy}

 

The following images show where you can obtain those values in the Azure Portal.

 

{Your Azure B2C Domain Name}

image

 

{Your Application (client) ID}

image

 

{Your Signup policy}

image

 

Update The Blazor Program

image

Select Manage NuGet Packages and install the following NuGet packages:

  • Microsoft.AspNetCore.Authentication.JwtBearer
  • Microsoft.AspNetCore.Authentication.OpenIdConnect
  • Microsoft.Identity.Web
  • Microsoft.Identity.Web.UI

 

 

image

Open the Program.cs file with the following code:

 

using BlazorAzureB2C.Components;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web.UI;
using Microsoft.Identity.Web;
using System.Reflection;
using System.Security.Claims;
using System.Linq.Dynamic.Core;
namespace BlazorAzureB2C
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);
            // Read the connection string from the appsettings.json file
            builder.Configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
            // Get HostingEnvironment
            var env = builder.Environment;
            builder.Configuration.AddJsonFile($"appsettings{env.EnvironmentName}.json", optional: true);
            builder.Configuration.AddEnvironmentVariables()
                .AddUserSecrets(Assembly.GetExecutingAssembly(), true);
            // Add services to the container.
            builder.Services.AddRazorComponents()
                .AddInteractiveServerComponents()
                .AddMicrosoftIdentityConsentHandler();
            builder.Services.AddCascadingAuthenticationState();
            builder.Services.AddHttpClient();
            builder.Services.AddHttpContextAccessor();
            builder.Services.AddScoped<HttpContextAccessor>();
            // This is where you wire up to events to detect when a user Log in
            builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
                .AddMicrosoftIdentityWebApp(options =>
                {
                    builder.Configuration.Bind("AzureAdB2C", options);
                    options.Events = new OpenIdConnectEvents
                    {
                        OnRedirectToIdentityProvider = async ctxt =>
                        {
                            // Invoked before redirecting to the identity provider to authenticate. 
                            // This can be used to set ProtocolMessage.State
                            // that will be persisted through the authentication process. 
                            // The ProtocolMessage can also be used to add or customize
                            // parameters sent to the identity provider.
                            await Task.Yield();
                        },
                        OnAuthenticationFailed = async ctxt =>
                        {
                            // They tried to log in but it failed
                            await Task.Yield();
                        },
                        OnSignedOutCallbackRedirect = async ctxt =>
                        {
                            ctxt.HttpContext.Response.Redirect(ctxt.Options.SignedOutRedirectUri);
                            ctxt.HandleResponse();
                            await Task.Yield();
                        },
                        OnTicketReceived = async ctxt =>
                        {
                            if (ctxt.Principal != null)
                            {
                                if (ctxt.Principal.Identity is ClaimsIdentity identity)
                                {
                                    var colClaims = await ctxt.Principal.Claims.ToDynamicListAsync();
                                    var IdentityProvider = colClaims.FirstOrDefault(
                                        c => c.Type == "http://schemas.microsoft.com/identity/claims/identityprovider")?.Value;
                                    var Objectidentifier = colClaims.FirstOrDefault(
                                        c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")?.Value;
                                    var EmailAddress = colClaims.FirstOrDefault(
                                        c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress")?.Value;
                                    var FirstName = colClaims.FirstOrDefault(
                                        c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname")?.Value;
                                    var LastName = colClaims.FirstOrDefault(
                                        c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname")?.Value;
                                    var AzureB2CFlow = colClaims.FirstOrDefault(
                                        c => c.Type == "http://schemas.microsoft.com/claims/authnclassreference")?.Value;
                                    var auth_time = colClaims.FirstOrDefault(
                                        c => c.Type == "auth_time")?.Value;
                                    var DisplayName = colClaims.FirstOrDefault(
                                        c => c.Type == "name")?.Value;
                                    var idp_access_token = colClaims.FirstOrDefault(
                                        c => c.Type == "idp_access_token")?.Value;
                                }
                            }
                            await Task.Yield();
                        },
                    };
                });
            builder.Services.AddControllersWithViews()
                .AddMicrosoftIdentityUI();
            var app = builder.Build();
            // Configure the HTTP request pipeline.
            if (!app.Environment.IsDevelopment())
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.MapControllers();
            app.UseAntiforgery();
            app.MapRazorComponents<App>()
                .AddInteractiveServerRenderMode();
            app.Run();
        }
    }
}

image

Open _Imports.razor and add the following line:

 

@using Microsoft.AspNetCore.Components.Authorization

 

image

Open the MainLayout.razor page and replace all the code with the following code:

 

@inherits LayoutComponentBase
<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>
    <main>
        <div class="top-row px-4">
            <AuthorizeView>
                <Authorized>
                    Hello @context.User.Identity?.Name!
                    <a href="MicrosoftIdentity/Account/SignOut">Log out</a>
                </Authorized>
                <NotAuthorized>
                    <a href="/MicrosoftIdentity/Account/SignIn">Sign in with your social account</a>
                </NotAuthorized>
            </AuthorizeView>
        </div>
        <article class="content px-4">
            @Body
        </article>
    </main>
</div>
<div id="blazor-error-ui">
    An unhandled error has occurred.
    <a href="" class="reload">Reload</a>
    <a class="dismiss"></a>
</div>

 

 

Sign-In To Azure B2C

image

In Visual Studio, Hit F5 to run the application.

 

image

Click the button to sign in.

 

image

Your web browser will open and the login will display.

Log in with your Microsoft account.

 

image

If this is your first time logging in, a new user screen will display.

 

image

Enter a Display Name and an Email address, and click the Send verification code button.

 

image

An email will be sent to the email address with a code.

 

image

Enter the code and click the Verify code button.

 

image

Finally, enter a First Name and Last Name in the last two boxes and click the Continue button.

 

image

You will be logged in.

 

image

If you return to the Azure Portal and select Users

 

image

You will be able to search for and select the user.

 

image

You will be able to fully manage the user, including implementing Conditional Access policies.

 

Download

The project is available on the Downloads page on this site.

You must have Visual Studio 2022 (or higher) installed to run the code.

 

Links

Creating A Blazor WebAssembly Azure B2C Application

Blazor and Azure B2C: The Big Picture

Blazor Azure B2C User And Group Management

ADefWebserver/BlazorSimpleSurvey: Blazor Simple Survey (github.com)

Azure Active Directory B2C documentation | Microsoft Docs

What is Azure Active Directory B2C? | Microsoft Docs

Azure AD B2C and MSAL.NET - Microsoft identity platform | Microsoft Docs

Migrate applications and APIs to b2clogin.com - Azure AD B2C | Microsoft Docs

A Walkthrough For Azure AD B2C Custom Policy (Identity Experience Framework) – tsmatz (wordpress.com)

An error has occurred. This application may no longer respond until reloaded. Reload 🗙