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:
You can download the example code used in this topic on GitHub.
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.
Microsoft.AspNetCore.Components.Authorization and System.IdentityModel.Tokens.Jwt from the NuGet.@using Microsoft.AspNetCore.Components.Authorization to _Imports.razor.CascadingAuthenticationState as the root component in App.razor. For example:<CascadingAuthenticationState>
<Router AppAssembly="typeof(App).Assembly">
...
</Router>
</CascadingAuthenticationState>
public class AuthenticationDataMemoryStorage
{
public string Token { get; set; } = "";
}
AuthenticationStateProvider by create a new class that extends the AuthenticationStateProvider class. The following image illustrates the main objective of the GetAuthenticationStateAsync method.
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;
}
}

Code sample:
public async Task LoginAsync()
{
string token = await _httpClient.GetStringAsync("example-data/token.json");
_authenticationDataMemoryStorage.Token = token;
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}

For example:
public void Logout()
{
_authenticationDataMemoryStorage.Token = "";
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}
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>
The user information is stored at the ClaimPrincipal.Claims. To access to the user information, you need to:
AuthenticationStateProvider class, create a property to store the information that you want to access. For example:public string Username { get; set; } = "";
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 theClaimwith the typeClaimTypes.NameIdentifier. If you use another claim type, you need to change the code accordingly.
AuthenticationStateChanged event. For example:public BlazorSchoolAuthenticationStateProvider(HttpClient httpClient, AuthenticationDataMemoryStorage authenticationDataMemoryStorage)
{
...
AuthenticationStateChanged += OnAuthenticationStateChanged;
}
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>
In this section, we have collected some common mistakes from the Blazor School Discord Community.
ClaimsIdentity without the authenticationTypeIn 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.
authenticationType?The ClaimsIdentity will mark the user as unauthenticated, the property ClaimsIdentity.IsAuthenticated will be false.
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.
GetAuthenticationStateAsync from AuthenticationStateProvider to get the user's informationThe 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 ?? "";
}
}
}
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:
HttpContextAccessor to get the user informationThe 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.