Authentication in a Blazor application is very similar to any web application. Especially if you are building a Blazor Server application, where authentication is identical to any ASP.NET Core application. But in Blazor WebAssembly applications you don’t have a back-end on your server. Everything lives on the client. This means that you for instance cannot have any secrets in your application.

Luckily there is a JavaScript version of the Microsoft Authentication Library that you can use with any web application. That is true also for Blazor applications, both server and WebAssembly.

I wanted to create a library for Blazor applications that you can use consistently in both Blazor Server and Blazor WebAssembly applications. This turned into yet another Blazorade library – Blazorade MSAL. This article shows you how you can use Blazorade MSAL to easily manage authentication in your Blazor applications. With this library, Blazor authentication just became a bit simpler.

If you want to read more about Blazor and Blazorade, check out my other articles on both Blazor and Blazorade.

Comparing to the WebAssembly Authentication Library for ASP.NET Core

I know that there is the Microsoft.AspNetCore.Components.WebAssembly.Authentication Nuget package from Microsoft. You can read more about how to use that library in your application in the docs. I’m not trying to compete with that in any way. that would be unwise. Instead, I just try to provide an alternative with a little different approach.

The main difference is that the WebAssembly Authentication library is more focused on protecting your routes and pages with authentication. You define the pages and routes that need authentication. Blazorade MSAL is more focused on protecting certain functionality.

What I mean by that is that with Blazorade MSAL, your Blazor authentication becomes more on-demand. You get an identity token or access token when you need it in your code. Blazor applications are Single-Page Applications (SPAs) that don’t act as traditional web pages – They don’t load the entire page. Instead, parts of the page are updated in response to user action. So with Blazorade MSAL, you can sync your token acquisitions with your user actions.

I’ll give you a simple example. You have an application that displays a user’s e-mail inbox. For that your application needs to have the Mail.Read permission. But, if the user decides that they also want to send out an e-mail, your application would need to request for the Mail.Send permission too. Your application could request that permission only when needed, and not when the page or component is loaded.

Creating a Sample Application

In the chapters below, I’ll go through all the necessary steps you need to take to build an application that handles Blazor authentication with Blazorade MSAL. The sample shows how you get the tokens that you can use to access for instance Microsoft Graph on behalf of your user. It also shows you how you can get an access token with additional permissions in response to user action. This keeps the sample code as simple as possible, so that we can focus on the main thing. You can then easily apply that to your needs.

Create a New Blazor WebAssembly Application

Just to show you how easy it is to use Blazorade MSAL to handle authentication in your Blazor WebAssembly application, I’ll use a WebAssembly application in this sample. The way you would use Blazorade MSAL in a Blazor Server application is very similar, mostly identical to what it is in a Blazor WebAssembly application. The only difference actually is where you store your application settings, and how you load those settings in during your application startup. I will highlight those differences below when there are differences.

So, create a Blazor WebAssembly application with .NET 5 as shown below.

Project creation dialog in Visual Studio 2019 showing how to create a Blazor WebAssembly application using .NET 5.

Make sure that the Configure for HTTPS is selected. Even though not explicitly required by Azure AD, it is a good habit to run your applications on HTTPS. Don’t select the ASP.NET Core hosted or Progressive Web Application checkboxes. Blazorade MSAL will work in those cases too, but in this sample, I’ll stick to as simple as possible.

When the application is created, run it by pressing F5, and take note of the URL it loads on. It will be different for you, but for me it is https://localhost:44377/. You will need this when registering your application with Azure AD.

Naturally, when you deploy your application to a server, either Azure, or some other hosting provider, the URL will be different. We’ll go with the localhost URL in this sample.

Add Reference to Blazorade MSAL

Blazorade MSAL is open source, so in theory, you could add the Blazorade MSAL repository as a submodule to your Git repository, and use it as source code in your application. A much easier way is to add a reference directly from Nuget.

When you have it referenced, locate the _Imports.razor file in your application, and add the following lines to it.

@using Blazorade.Msal.Components
@using Blazorade.Msal.Security
@using Blazorade.Msal.Services

Create a Login Page

A login page is only needed if you intend to use redirect login mode in your application. With Microsoft Authentication Library, you can basically handle user interaction in two different ways. Either your users will be redirected to Azure AD (or any other login provider) for logging in, and then redirected back to your application. Or, you can configure your application to show a popup window that will handle the user interaction.

Personally, I like the popup mode better, because that will ensure that the user’s context is not lost in case they must log in. You just pop up a login window, and when everything is complete, the login window will close and your application will get the access token.

However, with some browsers and in some circumstances, popups may cause problems, so you might want to consider the redirect mode too.

Well, anyway, if you intend to use the redirect interaction mode, you need to create a login page. This page will handle the response sent to your application with all the necessary codes that MSAL uses to acquire the tokens your application needs.

So, locate the Pages folder in your application, and add a new Razor component to the folder. Let’s call it Login.razor. Then clear out all code in the file, and add the following code to it.

@page "/login" 
@inject NavigationManager NavMan

<LoginRedirectHandler OnLoginSucceeded='() => this.NavMan.NavigateTo("/")'>
    <p>Processing login. Please hang in there...</p>

That’s all! The contents of the LoginRedirectHandler component can be anything you want to show on the login page. Of course, you could modify the login page in many ways, but this gets the job done. For instance, you might want to handle errors on the login page too. You can do that by adding an event handler on the LoginRedirectHandler component’s OnLoginFailed event.

Register Your Azure AD Application

To have Azure AD issue access tokens to your application, Azure AD needs to have a record of your application. You do this by registering your application with Azure AD.

Log in to the Azure AD management portal for your tenant you want to publish the application in. Then, navigate to the app registrations blade. Add a new application by clicking the New registration button. Then, type in the following information on the application.

  • Name: Whatever you want to call your application. This will also be shown to your users when they log in and grant the permissions your application is requesting.
  • Supported account types: Here you can select any type of account you want. I’ll just go with the default single-tenant application.
  • Redirect URI: In the dropdown, select Single-page application (SPA), and type in the URI of your login page. For me, it would be https://localhost:44377/login. Your application will most likely have a different port number. If you chose something else as route for your login page, you need to change the redirect URI accordingly.

Click Register to create the application.

Configure Application Settings

Locate the wwwroot folder in your application, and add an appsettings.json file to that folder. This file will contain all the necessary configuration for your application. Paste in the following into that file.

  "myapp": {
    "clientId": "<Application (client) ID of your application>",
    "tenantId": "<your tenant>"

The clientId attribute contains the application ID of your application. The tenantId can be either the full name of your tenant, the guid that represents your tenant, or a vanity domain that you have registered with your tenant.

Important! Since this is a Blazor WebAssembly application, everything that you publish to your hosting provider is downloaded to the clients in order for your application to run. This includes all of your application settings too. This means that you must not add any sensitive data into your settings file.

In a Blazor Server application, you have one settings file for each environment. By default, in the root folder of your application, you have a appsettings.json and a appsettings.Development.json file where you would store these settings.

Add Necessary Startup Code

Open the Program.cs file in the root of your application. Add the following using statement to the list of using statements at the top of the file.

using Blazorade.Msal.Configuration;

Then, in the Main method, just before the last line of code (await builder.Build().RunAsync();), add the following.

builder.Services.AddBlazoradeMsal((sp, options) =>
    var appSettings = sp.GetService<IConfiguration>().GetSection("myapp");
    options.ClientId = appSettings.GetValue<string>("clientId");
    options.TenantId = appSettings.GetValue<string>("tenantId");

    options.DefaultScopes = new string[] { "openid", "profile" };
    options.InteractiveLoginMode = InteractiveLoginMode.Redirect;
    options.RedirectUrl = "/login";
    options.TokenCacheScope = TokenCacheScope.Persistent;

DefaultScopes defines the set of scopes that your application will request when acquiring for tokens, if not explicitly requesting more. By default, Blazorade MSAL defines openid and profile as scopes. The line 7 in the code snippet above is not needed, unless you set your default scopes to something else. I just wanted to show you that you can define default scopes with Blazorade MSAL.

The RedirectUrl will point to your login page. If you are not going to use redirect login, then you can skip this. However, you can have it configured regardless of the interactive mode you select. It only applies to redirect mode.

With the TokenCacheScope you specify how tokens are cached. The default is Session, which does not cache tokens across browser sessions. You may also find that some browsers don’t share session level information across multiple browser tabs. Persistent will keep the tokens cached across browser sessions. So, when your users come back, they don’t have to log in again. MSAL will also take care of refreshing the tokens when they expire.

In a Blazor Server application, you would add the startup code to the Startup class and the ConfigureServices method. The code is the same. You just put it in a different place.

Request Access Tokens in the Application

OK, so now all setup is complete, and it’s time to start writing some code! We’ll create all of the sample in a separate component, which you then can put on any of your pages, like the front page Index.razor in the Pages folder.

Open the Shared folder, and add a new Razor component. Let’s call it MSALDemo.razor. Clear everything from the file, and paste in the following code.

@inject BlazoradeMsalService MsalService

    private AuthenticationResult authResult;

    private async Task AcquireTokenAsync(params string[] scopes)
        authResult = await this.MsalService.AcquireTokenAsync(new TokenAcquisitionRequest
            Scopes = scopes,
            FallbackToDefaultLoginHint = true

<h2>Blazorade MSAL Demo</h2>
<div class="btn-group">
    <button type="button" class="btn btn-outline-primary" @onclick='async () => { await this.AcquireTokenAsync(); }'>Default Scopes</button>
    <button type="button" class="btn btn-outline-secondary" @onclick='async () => { await this.AcquireTokenAsync("Mail.Read"); }'>Mail.Read</button>
    <button type="button" class="btn btn-outline-secondary" @onclick='async () => { await this.AcquireTokenAsync("Mail.Read", "Mail.Send"); }'>Mail.Read, Mail.Send</button>

@if (null != this.authResult)
        <li>Username: @this.authResult.Account?.UserName</li>
        <li>Expires: @this.authResult.ExpiresOn</li>
        <li>Scopes: @string.Join(", ", this.authResult.Scopes)</li>
        <li><a href="" target="_blank">Access Token</a>: @this.authResult.AccessToken</li>
        <li><a href="" target="_blank">Id Token</a>: @this.authResult.IdToken</li>

So, what you basically have here is three buttons. When you click on the first button that says Default Scopes, the code will use Blazorade MSAL to acquire a token that grants access to the scopes you defined as your default scopes in your Program class. When you click on the other two buttons, the code will again acquire a token with scopes defined in the button click event hander.

After you’ve added this component to your Index.razor file. You can run it to try out Blazor authentication with Blazorade MSAL. I removed everything else from that page except the MSALDemo component, so the code looks like this.

@page "/"

<MSALDemo />

Now, when you run the application and click one of the buttons to acquire a token, a popup window will pop up and ask you to log in. If you haven’t consented to the scopes acquired, you will also be asked to consent. If you are logging on as a global administrator of your tenant, you can choose to consent on behalf of all users in your tenant.

Feel free to play around with the code and change the scopes acquired.


Hope this gives you a better picture of what you can do with Blazorade MSAL. If you find some problems with it, please feel free to file an issue, and we’ll have a look.


Leave a Reply

Your email address will not be published. Required fields are marked *