ASP.NET Core Blazor authentication state
Note
This isn't the latest version of this article. For the current release, see the .NET 8 version of this article.
Warning
This version of ASP.NET Core is no longer supported. For more information, see .NET and .NET Core Support Policy. For the current release, see the .NET 8 version of this article.
Important
This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
For the current release, see the .NET 8 version of this article.
This article explains how to create a custom authentication state provider and receive user authentication state change notifications in code.
The general approaches taken for server-side and client-side Blazor apps are similar but differ in their exact implementations, so this article pivots between server-side Blazor apps and client-side Blazor apps. Use the pivot selector at the top of the article to change the article's pivot to match the type of Blazor project that you're working with:
- Server-side Blazor apps (Server pivot): Blazor Server for .NET 7 or earlier and the server project of a Blazor Web App for .NET 8 or later.
- Client-side Blazor apps (Blazor WebAssembly pivot): Blazor WebAssembly for all versions of .NET or the
.Client
project of a Blazor Web App for .NET 8 or later.
Abstract AuthenticationStateProvider
class
The Blazor framework includes an abstract AuthenticationStateProvider class to provide information about the authentication state of the current user with the following members:
- GetAuthenticationStateAsync: Asynchronously gets the authentication state of the current user.
- AuthenticationStateChanged: An event that provides notification when the authentication state has changed. For example, this event may be raised if a user signs in or out of the app.
- NotifyAuthenticationStateChanged: Raises an authentication state changed event.
Implement a custom AuthenticationStateProvider
The app must reference the Microsoft.AspNetCore.Components.Authorization
NuGet package, which provides authentication and authorization support for Blazor apps.
Note
For guidance on adding packages to .NET apps, see the articles under Install and manage packages at Package consumption workflow (NuGet documentation). Confirm correct package versions at NuGet.org.
Configure the following authentication, authorization, and cascading authentication state services in the Program
file.
When you create a Blazor app from one of the Blazor project templates with authentication enabled, the app is preconfigured with the following service registrations, which includes exposing the authentication state as a cascading parameter. For more information, see ASP.NET Core Blazor authentication and authorization with additional information presented in the article's Customize unauthorized content with the Router
component section.
using Microsoft.AspNetCore.Components.Authorization;
...
builder.Services.AddAuthorization();
builder.Services.AddCascadingAuthenticationState();
Configure authentication and authorization services in the Program
file.
When you create a Blazor app from one of the Blazor project templates with authentication enabled, the app includes the following service registration.
using Microsoft.AspNetCore.Components.Authorization;
...
builder.Services.AddAuthorization();
Configure authentication and authorization services in Startup.ConfigureServices
of Startup.cs
.
When you create a Blazor app from one of the Blazor project templates with authentication enabled, the app includes the following service registration.
using Microsoft.AspNetCore.Components.Authorization;
...
services.AddAuthorization();
In Blazor WebAssembly apps (all .NET versions) or the .Client
project of a Blazor Web App (.NET 8 or later), configure authentication, authorization, and cascading authentication state services in the Program
file.
When you create a Blazor app from one of the Blazor project templates with authentication enabled, the app is preconfigured with the following service registrations, which includes exposing the authentication state as a cascading parameter. For more information, see ASP.NET Core Blazor authentication and authorization with additional information presented in the article's Customize unauthorized content with the Router
component section.
using Microsoft.AspNetCore.Components.Authorization;
...
builder.Services.AddAuthorizationCore();
builder.Services.AddCascadingAuthenticationState();
Configure authentication and authorization services in the Program
file.
When you create a Blazor app from one of the Blazor project templates with authentication enabled, the app includes the following service registration.
using Microsoft.AspNetCore.Components.Authorization;
...
builder.Services.AddAuthorizationCore();
Subclass AuthenticationStateProvider and override GetAuthenticationStateAsync to create the user's authentication state. In the following example, all users are authenticated with the username mrfibuli
.
CustomAuthStateProvider.cs
:
using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
public class CustomAuthStateProvider : AuthenticationStateProvider
{
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
var identity = new ClaimsIdentity(
[
new Claim(ClaimTypes.Name, "mrfibuli"),
], "Custom Authentication");
var user = new ClaimsPrincipal(identity);
return Task.FromResult(new AuthenticationState(user));
}
}
Note
The preceding code that creates a new ClaimsIdentity uses simplified collection initialization introduced with C# 12 (.NET 8). For more information, see Collection expressions - C# language reference.
The CustomAuthStateProvider
service is registered in the Program
file. Register the service scoped with AddScoped:
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();
In a Blazor Server app, register the service scoped with AddScoped after the call to AddServerSideBlazor:
builder.Services.AddServerSideBlazor();
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();
In a Blazor Server app, register the service scoped with AddScoped after the call to AddServerSideBlazor:
services.AddServerSideBlazor();
services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();
The CustomAuthStateProvider
service is registered in the Program
file. Register the service singleton with AddSingleton:
builder.Services.AddSingleton<AuthenticationStateProvider, CustomAuthStateProvider>();
If it isn't present, add an @using
statement to the _Imports.razor
file to make the Microsoft.AspNetCore.Components.Authorization namespace available across components:
@using Microsoft.AspNetCore.Components.Authorization;
Confirm or change the route view component to an AuthorizeRouteView in the Router component definition. The location of the Router
component differs depending on the type of app. Use search to locate the component if you're unaware of its location in the project.
<Router ...>
<Found ...>
<AuthorizeRouteView RouteData="routeData"
DefaultLayout="typeof(Layout.MainLayout)" />
...
</Found>
</Router>
Note
When you create a Blazor app from one of the Blazor project templates with authentication enabled, the app includes the AuthorizeRouteView component. For more information, see ASP.NET Core Blazor authentication and authorization with additional information presented in the article's Customize unauthorized content with the Router
component section.
Where the Router component is located:
- Confirm or change the route view component to an AuthorizeRouteView.
- Confirm or add a CascadingAuthenticationState component around the Router component.
The location of the Router
component differs depending on the type of app. Use search to locate the component if you're unaware of its location in the project.
<CascadingAuthenticationState>
<Router ...>
<Found ...>
<AuthorizeRouteView RouteData="routeData"
DefaultLayout="typeof(MainLayout)" />
...
</Found>
</Router>
</CascadingAuthenticationState>
Note
When you create a Blazor app from one of the Blazor project templates with authentication enabled, the app includes the AuthorizeRouteView and CascadingAuthenticationState components. For more information, see ASP.NET Core Blazor authentication and authorization with additional information presented in the article's Customize unauthorized content with the Router
component section.
The following example AuthorizeView component demonstrates the authenticated user's name:
<AuthorizeView>
<Authorized>
<p>Hello, @context.User.Identity?.Name!</p>
</Authorized>
<NotAuthorized>
<p>You're not authorized.</p>
</NotAuthorized>
</AuthorizeView>
For guidance on the use of AuthorizeView, see ASP.NET Core Blazor authentication and authorization.
Authentication state change notifications
A custom AuthenticationStateProvider
can invoke NotifyAuthenticationStateChanged on the AuthenticationStateProvider base class to notify consumers of the authentication state change to rerender.
The following example is based on implementing a custom AuthenticationStateProvider by following the guidance in the Implement a custom AuthenticationStateProvider
section earlier in this article. If you already followed the guidance in that section, the following CustomAuthStateProvider
replaces the one shown in the section.
The following CustomAuthStateProvider
implementation exposes a custom method, AuthenticateUser
, to sign in a user and notify consumers of the authentication state change.
CustomAuthStateProvider.cs
:
using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
public class CustomAuthStateProvider : AuthenticationStateProvider
{
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
var identity = new ClaimsIdentity();
var user = new ClaimsPrincipal(identity);
return Task.FromResult(new AuthenticationState(user));
}
public void AuthenticateUser(string userIdentifier)
{
var identity = new ClaimsIdentity(
[
new Claim(ClaimTypes.Name, userIdentifier),
], "Custom Authentication");
var user = new ClaimsPrincipal(identity);
NotifyAuthenticationStateChanged(
Task.FromResult(new AuthenticationState(user)));
}
}
Note
The preceding code that creates a new ClaimsIdentity uses simplified collection initialization introduced with C# 12 (.NET 8). For more information, see Collection expressions - C# language reference.
In a component:
- Inject AuthenticationStateProvider.
- Add a field to hold the user's identifier.
- Add a button and a method to cast the AuthenticationStateProvider to
CustomAuthStateProvider
and callAuthenticateUser
with the user's identifier.
@inject AuthenticationStateProvider AuthenticationStateProvider
<input @bind="userIdentifier" />
<button @onclick="SignIn">Sign in</button>
<AuthorizeView>
<Authorized>
<p>Hello, @context.User.Identity?.Name!</p>
</Authorized>
<NotAuthorized>
<p>You're not authorized.</p>
</NotAuthorized>
</AuthorizeView>
@code {
public string userIdentifier = string.Empty;
private void SignIn()
{
((CustomAuthStateProvider)AuthenticationStateProvider)
.AuthenticateUser(userIdentifier);
}
}
The preceding approach can be enhanced to trigger notifications of authentication state changes via a custom service. The following CustomAuthenticationService
class maintains the current user's claims principal in a backing field (currentUser
) with an event (UserChanged
) that the authentication state provider can subscribe to, where the event invokes NotifyAuthenticationStateChanged. With the additional configuration later in this section, the CustomAuthenticationService
can be injected into a component with logic that sets the CurrentUser
to trigger the UserChanged
event.
CustomAuthenticationService.cs
:
using System.Security.Claims;
public class CustomAuthenticationService
{
public event Action<ClaimsPrincipal>? UserChanged;
private ClaimsPrincipal? currentUser;
public ClaimsPrincipal CurrentUser
{
get { return currentUser ?? new(); }
set
{
currentUser = value;
if (UserChanged is not null)
{
UserChanged(currentUser);
}
}
}
}
In the Program
file, register the CustomAuthenticationService
in the dependency injection container:
builder.Services.AddScoped<CustomAuthenticationService>();
In Startup.ConfigureServices
of Startup.cs
, register the CustomAuthenticationService
in the dependency injection container:
services.AddScoped<CustomAuthenticationService>();
In the Program
file, register the CustomAuthenticationService
in the dependency injection container:
builder.Services.AddSingleton<CustomAuthenticationService>();
The following CustomAuthStateProvider
subscribes to the CustomAuthenticationService.UserChanged
event. The GetAuthenticationStateAsync
method returns the user's authentication state. Initially, the authentication state is based on the value of the CustomAuthenticationService.CurrentUser
. When the user changes, a new authentication state is created for the new user (new AuthenticationState(newUser)
) for calls to GetAuthenticationStateAsync
:
using Microsoft.AspNetCore.Components.Authorization;
public class CustomAuthStateProvider : AuthenticationStateProvider
{
private AuthenticationState authenticationState;
public CustomAuthStateProvider(CustomAuthenticationService service)
{
authenticationState = new AuthenticationState(service.CurrentUser);
service.UserChanged += (newUser) =>
{
authenticationState = new AuthenticationState(newUser);
NotifyAuthenticationStateChanged(Task.FromResult(authenticationState));
};
}
public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
Task.FromResult(authenticationState);
}
The following component's SignIn
method creates a claims principal for the user's identifier to set on CustomAuthenticationService.CurrentUser
:
@using System.Security.Claims
@inject CustomAuthenticationService AuthService
<input @bind="userIdentifier" />
<button @onclick="SignIn">Sign in</button>
<AuthorizeView>
<Authorized>
<p>Hello, @context.User.Identity?.Name!</p>
</Authorized>
<NotAuthorized>
<p>You're not authorized.</p>
</NotAuthorized>
</AuthorizeView>
@code {
public string userIdentifier = string.Empty;
private void SignIn()
{
var currentUser = AuthService.CurrentUser;
var identity = new ClaimsIdentity(
[
new Claim(ClaimTypes.Name, userIdentifier),
],
"Custom Authentication");
var newUser = new ClaimsPrincipal(identity);
AuthService.CurrentUser = newUser;
}
}
Note
The preceding code that creates a new ClaimsIdentity uses simplified collection initialization introduced with C# 12 (.NET 8). For more information, see Collection expressions - C# language reference.
Additional resources
- Server-side unauthorized content display while prerendering with a custom
AuthenticationStateProvider
- How to access an
AuthenticationStateProvider
from aDelegatingHandler
set up using anIHttpClientFactory
- Secure an ASP.NET Core Blazor Web App with OpenID Connect (OIDC)
- Secure ASP.NET Core Blazor WebAssembly with ASP.NET Core Identity
- Server-side unauthorized content display while prerendering with a custom
AuthenticationStateProvider
- How to access an
AuthenticationStateProvider
from aDelegatingHandler
set up using anIHttpClientFactory
- Secure an ASP.NET Core Blazor Web App with OpenID Connect (OIDC)
- Secure ASP.NET Core Blazor WebAssembly with ASP.NET Core Identity Prerendering with authentication in hosted Blazor WebAssembly apps
ASP.NET Core