Implementing authentication

This tutorial will walk you through step by step on how to authenticate a user and display the user's information once authenticated. In this tutorial:

  • Required NuGet libraries.
  • Building authentication.
  • Access the user information.
  • Common mistakes.
You can download the example code used in this topic on GitHub.

Required NuGet libraries

Before you begin, you need to install Microsoft.AspNetCore.Components.Authorization. You also need to install additional NuGet packages based on your identity platform. For example, if you are using JWT, you will need to install System.IdentityModel.Tokens.Jwt.


Building authentication

  1. Install required NuGet libraries. In the example, we are going to use JWT, so we will need to install Microsoft.AspNetCore.Components.Authorization and System.IdentityModel.Tokens.Jwt from the NuGet.
  2. Add @using Microsoft.AspNetCore.Components.Authorization to _Imports.razor.
  3. Add CascadingAuthenticationState as the root component in App.razor. For example:
<CascadingAuthenticationState>
    <Router AppAssembly="typeof(App).Assembly">
        ...
    </Router>
</CascadingAuthenticationState>
  1. Add a browser storage for authentication. In this case, we will use memory storage for the sake of simplicity. In the real project, you can use local storage and session storage as you need.
public class AuthenticationDataMemoryStorage
{
    public string Token { get; set; } = "";
}
  1. Add your authenticate logic to the AuthenticationStateProvider by create a new class that extends the AuthenticationStateProvider class. The following image illustrates the main objective of the GetAuthenticationStateAsync method.

get-authentication-state-async.png

Code sample:

public class BlazorSchoolAuthenticationStateProvider : AuthenticationStateProvider
{
    private readonly HttpClient _httpClient;
    private readonly AuthenticationDataMemoryStorage _authenticationDataMemoryStorage;

    public BlazorSchoolAuthenticationStateProvider(HttpClient httpClient, AuthenticationDataMemoryStorage authenticationDataMemoryStorage)
    {
        _httpClient = httpClient;
        _authenticationDataMemoryStorage = authenticationDataMemoryStorage;
    }

    public override Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var identity = new ClaimsIdentity();

        if (tokenHandler.CanReadToken(_authenticationDataMemoryStorage.Token))
        {
            var jwtSecurityToken = tokenHandler.ReadJwtToken(_authenticationDataMemoryStorage.Token);
            identity = new ClaimsIdentity(jwtSecurityToken.Claims, "Blazor School");
        }

        var principal = new ClaimsPrincipal(identity);
        var authenticationState = new AuthenticationState(principal);
        var authenticationTask = Task.FromResult(authenticationState);

        return authenticationTask;
    }
}
  1. Add a method for the user to login. The following image illustrates the login flow:

login-flow.png

Code sample:

public async Task LoginAsync()
{
    string token = await _httpClient.GetStringAsync("example-data/token.json");
    _authenticationDataMemoryStorage.Token = token;
    NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}
  1. Add a method for the user to logout. The following image illustrates the logout flow:

logout-flow.png

For example:

public void Logout()
{
    _authenticationDataMemoryStorage.Token = "";
    NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}
  1. Register the browser storage accessor, the custom AuthenticationStateProvider at Program.cs. For example:
builder.Services.AddScoped<AuthenticationDataMemoryStorage>();
builder.Services.AddScoped<BlazorSchoolAuthenticationStateProvider>();
builder.Services.AddScoped<AuthenticationStateProvider>(sp => sp.GetRequiredService<BlazorSchoolAuthenticationStateProvider>());
builder.Services.AddAuthorizationCore();

After you have done all the steps, you can use the LoginAsync method to authenticate the users. For example:

@inject BlazorSchoolAuthenticationStateProvider BlazorSchoolAuthenticationStateProvider

<button @onclick="BlazorSchoolAuthenticationStateProvider.LoginAsync">Login</button>

Access the user information

The user information is stored at the ClaimPrincipal.Claims. To access to the user information, you need to:

  1. In your custom AuthenticationStateProvider class, create a property to store the information that you want to access. For example:
public string Username { get; set; } = "";
  1. Create a method to listen to the AuthenticationStateChanged event. In this method, store the user information to the property you have created at the previous step. For example:
private async void OnAuthenticationStateChanged(Task<AuthenticationState> task)
{
    var authenticationState = await task;

    if (authenticationState is not null)
    {
        Username = authenticationState.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value ?? "";
    }
}
In the example, we store the Claim with the type ClaimTypes.NameIdentifier. If you use another claim type, you need to change the code accordingly.
  1. In the constructor of the class, subscribe to the AuthenticationStateChanged event. For example:
public BlazorSchoolAuthenticationStateProvider(HttpClient httpClient, AuthenticationDataMemoryStorage authenticationDataMemoryStorage)
{
    ...
    AuthenticationStateChanged += OnAuthenticationStateChanged;
}
  1. Implement the IDisposable interface to unsubscribe the AuthenticationStateChanged event. For example:
public class BlazorSchoolAuthenticationStateProvider : AuthenticationStateProvider, IDisposable
{
    ...
    public void Dispose()
    {
        AuthenticationStateChanged -= OnAuthenticationStateChanged;
    }
}

After you have done all the steps, you can access the user information by the property in your custom AuthenticationStateProvider class. For example:

@inject BlazorSchoolAuthenticationStateProvider BlazorSchoolAuthenticationStateProvider

<AuthorizeView>
    <Authorized>
        <div>User: @BlazorSchoolAuthenticationStateProvider.Username</div>
    </Authorized>
</AuthorizeView>

Common mistakes

In this section, we have collected some common mistakes from the Blazor School Discord Community.

Mistake #1: Create ClaimsIdentity without the authenticationType

In the GetAuthenticationStateAsync method, you need to create a ClaimsIdentity, and from the ClaimsIdentity, create a ClaimsPrincipal. However, most people created ClaimsIdentity without the authenticationType. For example:

// Wrong
var identity = new ClaimsIdentity(claims);

This is the right way to create a ClaimsIdentity:

// Correct
var identity = new ClaimsIdentity(claims, "Blazor School");

In the example, the second parameter "Blazor School" is the authenticationType. The authenticationType can be any string you want.

What will happen if you don't include the authenticationType?

The ClaimsIdentity will mark the user as unauthenticated, the property ClaimsIdentity.IsAuthenticated will be false.

Mistake #2: Rely on CORS to do the security

CORS (Cross-Origin Resource Sharing) is a technique to prevent the API being accessed by the website from outside the list. However, CORS is enforced by the browser only. The attacker can send a request from outside the browser to access your API.

Mistake #3: Call the GetAuthenticationStateAsync from AuthenticationStateProvider to get the user's information

The GetAuthenticationStateAsync is not intended to be called in the component by AuthenticationStateProvider. For example, the following code is bad:

// Bad code
@inject BlazorSchoolAuthenticationStateProvider BlazorSchoolAuthenticationStateProvider

<div>@Username</div>

@code {
    public string Username { get; set; } = "";

    protected override async Task OnInitializedAsync()
    {
        var authenticationState = await BlazorSchoolAuthenticationStateProvider.GetAuthenticationStateAsync();

        if (authenticationState is not null)
        {
            Username = authenticationState.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value ?? "";
        }
    }
}

What will happen if you call the GetAuthenticationStateAsync from AuthenticationStateProvider to get the user's information?

The GetAuthenticationStateAsync will be executed whenever a component is rendered. The following video demonstrates this mistake:

Mistake #4: Use HttpContextAccessor to get the user information

The MVC and the Web API use HttpContextAccessor to get the user information. This creates a confusion in Blazor if you don't know how Blazor works. Blazor is an SPA framework, there will be only 1 request and that request cannot contain the user information. To get the information, follow the Access the user information in this tutorial.

BLAZOR SCHOOL
Designed and built with care by our dedicated team, with contributions from a supportive community. We strive to provide the best learning experience for our users.
Docs licensed CC-BY-SA-4.0
Copyright © 2021-2025 Blazor School
An unhandled error has occurred. Reload 🗙