ASP.NET Core Blazor authentication and authorization
Note
This isn't the latest version of this article. To switch to the latest, use the ASP.NET Core version selector at the top of the table of contents.
If the selector isn't visible in a narrow browser window, widen the window or select the vertical ellipsis (⋮) > Table of contents.
This article describes ASP.NET Core's support for the configuration and management of security in Blazor apps.
Security scenarios differ between Blazor Server and Blazor WebAssembly apps. Because Blazor Server apps run on the server, authorization checks are able to determine:
- The UI options presented to a user (for example, which menu entries are available to a user).
- Access rules for areas of the app and components.
Blazor WebAssembly apps run on the client. Authorization is only used to determine which UI options to show. Since client-side checks can be modified or bypassed by a user, a Blazor WebAssembly app can't enforce authorization access rules.
Razor Pages authorization conventions don't apply to routable Razor components. If a non-routable Razor component is embedded in a page of a Razor Pages app, the page's authorization conventions indirectly affect the Razor component along with the rest of the page's content.
ASP.NET Core Identity is designed to work in the context of HTTP request and response communication, which generally isn't the Blazor app client-server communication model. ASP.NET Core apps that use ASP.NET Core Identity for user management should use Razor Pages instead of Razor components for Identity-related UI, such as user registration, login, logout, and other user management tasks. Building Razor components that directly handle Identity tasks is possible for several scenarios but isn't recommended or supported by Microsoft.
ASP.NET Core abstractions, such as SignInManager<TUser> and UserManager<TUser>, aren't supported in Razor components. For more information on using ASP.NET Core Identity with Blazor, see Scaffold ASP.NET Core Identity into a Blazor Server app.
Authentication
Blazor uses the existing ASP.NET Core authentication mechanisms to establish the user's identity. The exact mechanism depends on how the Blazor app is hosted, Blazor Server or Blazor WebAssembly.
Blazor Server authentication
Blazor Server operates over a SignalR connection with the client. Authentication in SignalR-based apps is handled when the connection is established. Authentication can be based on a cookie or some other bearer token, but authentication is managed via the SignalR hub and entirely within the circuit.
The built-in AuthenticationStateProvider service for Blazor Server apps obtains authentication state data from ASP.NET Core's HttpContext.User
. This is how authentication state integrates with existing ASP.NET Core authentication mechanisms.
Avoid IHttpContextAccessor
/HttpContext
in Razor components
Don't use IHttpContextAccessor/HttpContext directly or indirectly in the Razor components of Blazor Server apps. Blazor apps run outside of the ASP.NET Core pipeline context. The HttpContext isn't guaranteed to be available within the IHttpContextAccessor, and HttpContext isn't guaranteed to hold the context that started the Blazor app.
The recommended approach for passing request state to the Blazor app is through root component parameters during the app's initial rendering. Alternatively, the app can copy the data into a scoped service in the root component's initialization lifecycle event for use across the app. For more information, see ASP.NET Core Blazor Server additional security scenarios.
A critical aspect of Blazor Server security is that the user attached to a given circuit might become updated at some point after the Blazor circuit is established but the IHttpContextAccessor isn't updated. For more information on addressing this situation with custom services, see ASP.NET Core Blazor Server additional security scenarios.
Shared state
Blazor server apps live in server memory, and multiple app sessions are hosted within the same process. For each app session, Blazor starts a circuit with its own dependency injection container scope, thus scoped services are unique per Blazor session.
Warning
We don't recommend apps on the same server share state using singleton services unless extreme care is taken, as this can introduce security vulnerabilities, such as leaking user state across circuits.
You can use stateful singleton services in Blazor apps if they're specifically designed for it. For example, use of a singleton memory cache is acceptable because a memory cache requires a key to access a given entry. Assuming users don't have control over the cache keys that are used with the cache, state stored in the cache doesn't leak across circuits.
For general guidance on state management, see ASP.NET Core Blazor state management.
Blazor WebAssembly authentication
In Blazor WebAssembly, authentication checks can be bypassed because all client-side code can be modified by users. The same is true for all client-side app technologies, including JavaScript SPA frameworks and native apps for any operating system.
Add the following:
A package reference for the
Microsoft.AspNetCore.Components.Authorization
NuGet package.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.
The Microsoft.AspNetCore.Components.Authorization namespace to the app's
_Imports.razor
file.
To handle authentication, use of the built-in or custom AuthenticationStateProvider service is covered in the following sections.
For more information, see Secure ASP.NET Core Blazor WebAssembly.
AuthenticationStateProvider
service
AuthenticationStateProvider is the underlying service used by the AuthorizeView component and CascadingAuthenticationState component to obtain the authentication state for a user.
You don't typically use AuthenticationStateProvider directly. Use the AuthorizeView
component or Task<AuthenticationState>
approaches described later in this article. The main drawback to using AuthenticationStateProvider directly is that the component isn't notified automatically if the underlying authentication state data changes.
Note
To implement a custom AuthenticationStateProvider, see Secure ASP.NET Core Blazor Server apps.
The AuthenticationStateProvider service can provide the current user's ClaimsPrincipal data, as shown in the following example.
Pages/ClaimsPrincipalData.razor
:
@page "/claims-principle-data"
@using System.Security.Claims
@inject AuthenticationStateProvider AuthenticationStateProvider
<h1>ClaimsPrincipal Data</h1>
<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>
<p>@authMessage</p>
@if (claims.Count() > 0)
{
<ul>
@foreach (var claim in claims)
{
<li>@claim.Type: @claim.Value</li>
}
</ul>
}
<p>@surname</p>
@code {
private string? authMessage;
private string? surname;
private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();
private async Task GetClaimsPrincipalData()
{
var authState = await AuthenticationStateProvider
.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity is not null && user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
claims = user.Claims;
surname = user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value;
}
else
{
authMessage = "The user is NOT authenticated.";
}
}
}
@page "/claims-principle-data"
@using System.Security.Claims
@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider
<h1>ClaimsPrincipal Data</h1>
<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>
<p>@authMessage</p>
@if (claims.Count() > 0)
{
<ul>
@foreach (var claim in claims)
{
<li>@claim.Type: @claim.Value</li>
}
</ul>
}
<p>@surname</p>
@code {
private string authMessage;
private string surname;
private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();
private async Task GetClaimsPrincipalData()
{
var authState = await AuthenticationStateProvider
.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
claims = user.Claims;
surname = user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value;
}
else
{
authMessage = "The user is NOT authenticated.";
}
}
}
If user.Identity.IsAuthenticated
is true
and because the user is a ClaimsPrincipal, claims can be enumerated and membership in roles evaluated.
For more information on dependency injection (DI) and services, see ASP.NET Core Blazor dependency injection and Dependency injection in ASP.NET Core. For information on how to implement a custom AuthenticationStateProvider in Blazor Server apps, see Secure ASP.NET Core Blazor Server apps.
Expose the authentication state as a cascading parameter
If authentication state data is required for procedural logic, such as when performing an action triggered by the user, obtain the authentication state data by defining a cascading parameter of type Task<
AuthenticationState>
, as the following example demonstrates.
Pages/CascadeAuthState.razor
:
@page "/cascade-auth-state"
<h1>Cascade Auth State</h1>
<p>@authMessage</p>
@code {
private string authMessage = "The user is NOT authenticated.";
[CascadingParameter]
private Task<AuthenticationState>? authenticationState { get; set; }
protected override async Task OnInitializedAsync()
{
if (authenticationState is not null)
{
var authState = await authenticationState;
var user = authState?.User;
if (user?.Identity is not null && user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
}
}
}
}
@page "/cascade-auth-state"
<h1>Cascade Auth State</h1>
<p>@authMessage</p>
@code {
private string authMessage = "The user is NOT authenticated.";
[CascadingParameter]
private Task<AuthenticationState> authenticationState { get; set; }
protected override async Task OnInitializedAsync()
{
if (authenticationState is not null)
{
var authState = await authenticationState;
var user = authState?.User;
if (user?.Identity is not null && user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
}
}
}
}
If user.Identity.IsAuthenticated
is true
, claims can be enumerated and membership in roles evaluated.
Set up the Task<
AuthenticationState>
cascading parameter using the AuthorizeRouteView and CascadingAuthenticationState components in the App
component.
Note
When you create a Blazor app from one of the Blazor project templates with authentication enabled, the App
component includes the AuthorizeRouteView and CascadingAuthenticationState components shown in the following example. A Blazor WebAssembly app includes the required service registrations as well. Additional information is presented in the Customize unauthorized content with the Router component section.
App.razor
:
<CascadingAuthenticationState>
<Router ...>
<Found ...>
<AuthorizeRouteView RouteData="@routeData"
DefaultLayout="@typeof(MainLayout)" />
...
</Found>
<NotFound>
...
</NotFound>
</Router>
</CascadingAuthenticationState>
Note
With the release of ASP.NET Core 5.0.1 and for any additional 5.x releases, the Router
component includes the PreferExactMatches
parameter set to @true
. For more information, see Migrate from ASP.NET Core 3.1 to 5.0.
In a Blazor WebAssembly App, add services for options and authorization to Program.cs
:
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
In a Blazor Server app, services for options and authorization are already present, so no further steps are required.
Authorization
After a user is authenticated, authorization rules are applied to control what the user can do.
Access is typically granted or denied based on whether:
- A user is authenticated (signed in).
- A user is in a role.
- A user has a claim.
- A policy is satisfied.
Each of these concepts is the same as in an ASP.NET Core MVC or Razor Pages app. For more information on ASP.NET Core security, see the articles under ASP.NET Core Security and Identity.
AuthorizeView
component
The AuthorizeView component selectively displays UI content depending on whether the user is authorized. This approach is useful when you only need to display data for the user and don't need to use the user's identity in procedural logic.
The component exposes a context
variable of type AuthenticationState (@context
in Razor syntax), which you can use to access information about the signed-in user:
<AuthorizeView>
<p>Hello, @context.User.Identity.Name!</p>
</AuthorizeView>
You can also supply different content for display if the user isn't authorized:
<AuthorizeView>
<Authorized>
<p>Hello, @context.User.Identity.Name!</p>
<p><button @onclick="SecureMethod">Authorized Only Button</button></p>
</Authorized>
<NotAuthorized>
<p>You're not authorized.</p>
</NotAuthorized>
</AuthorizeView>
@code {
private void SecureMethod() { ... }
}
A default event handler for an authorized element, such as the SecureMethod
method for the <button>
element in the preceding example, can only be invoked by an authorized user.
Warning
Client-side markup and methods associated with an AuthorizeView are only protected from view and execution in the rendered UI in Blazor WebAssembly apps. In order to protect authorized content and secure methods for Blazor WebAssembly apps, the content is usually supplied by a secure, authorized web API call to a server API and never stored in the app. For more information, see Call a web API from an ASP.NET Core Blazor app and ASP.NET Core Blazor WebAssembly additional security scenarios.
The content of <Authorized>
and <NotAuthorized>
tags can include arbitrary items, such as other interactive components.
Authorization conditions, such as roles or policies that control UI options or access, are covered in the Authorization section.
If authorization conditions aren't specified, AuthorizeView uses a default policy:
- Authenticated (signed-in) users are authorized.
- Unauthenticated (signed-out) users are unauthorized.
The AuthorizeView component can be used in the NavMenu
component (Shared/NavMenu.razor
) to display a NavLink
component (NavLink), but note that this approach only removes the list item from the rendered output. It doesn't prevent the user from navigating to the component. Implement authorization separately in the destination component.
Role-based and policy-based authorization
The AuthorizeView component supports role-based or policy-based authorization.
For role-based authorization, use the Roles parameter. In the following example, the user must have a role claim for either the Admin
or Superuser
roles:
<AuthorizeView Roles="Admin, Superuser">
<p>You have an 'Admin' or 'Superuser' role claim.</p>
</AuthorizeView>
To require a user have both Admin
and Superuser
role claims, nest AuthorizeView components:
<AuthorizeView Roles="Admin">
<p>User: @context.User</p>
<p>You have the 'Admin' role claim.</p>
<AuthorizeView Roles="Superuser" Context="innerContext">
<p>User: @innerContext.User</p>
<p>You have both 'Admin' and 'Superuser' role claims.</p>
</AuthorizeView>
</AuthorizeView>
The preceding code establishes a Context
for the inner AuthorizeView component to prevent an AuthenticationState context collision. The AuthenticationState context is accessed in the outer AuthorizeView with the standard approach for accessing the context (@context.User
). The context is accessed in the inner AuthorizeView with the named innerContext
context (@innerContext.User
).
For more information, including configuration guidance, see Role-based authorization in ASP.NET Core.
For policy-based authorization, use the Policy parameter with a single policy:
<AuthorizeView Policy="Over21">
<p>You satisfy the 'Over21' policy.</p>
</AuthorizeView>
To handle the case where the user should satisfy one of several policies, create a policy that confirms that the user satisfies other policies.
To handle the case where the user must satisfy several policies simultaneously, take either of the following approaches:
Create a policy for AuthorizeView that confirms that the user satisfies several other policies.
Nest the policies in multiple AuthorizeView components:
<AuthorizeView Policy="Over21"> <AuthorizeView Policy="LivesInCalifornia"> <p>You satisfy the 'Over21' and 'LivesInCalifornia' policies.</p> </AuthorizeView> </AuthorizeView>
Claims-based authorization is a special case of policy-based authorization. For example, you can define a policy that requires users to have a certain claim. For more information, see Policy-based authorization in ASP.NET Core.
If neither Roles nor Policy is specified, AuthorizeView uses the default policy:
- Authenticated (signed-in) users are authorized.
- Unauthenticated (signed-out) users are unauthorized.
Because .NET string comparisons are case-sensitive by default, matching role and policy names is also case-sensitive. For example, Admin
(uppercase A
) is not treated as the same role as admin
(lowercase a
).
Pascal case is typically used for role and policy names (for example, BillingAdministrator
), but the use of Pascal case isn't a strict requirement. Different casing schemes, such as camel case, kebab case, and snake case, are permitted. Using spaces in role and policy names is unusual but permitted by the framework. For example, billing administrator
is an unusual role or policy name format in .NET apps, but it's a valid role or policy name.
Content displayed during asynchronous authentication
Blazor allows for authentication state to be determined asynchronously. The primary scenario for this approach is in Blazor WebAssembly apps that make a request to an external endpoint for authentication.
While authentication is in progress, AuthorizeView displays no content by default. To display content while authentication occurs, use the <Authorizing>
tag:
<AuthorizeView>
<Authorized>
<p>Hello, @context.User.Identity.Name!</p>
</Authorized>
<Authorizing>
<p>You can only see this content while authentication is in progress.</p>
</Authorizing>
</AuthorizeView>
This approach isn't normally applicable to Blazor Server apps. Blazor Server apps know the authentication state as soon as the state is established. Authorizing content can be provided in a Blazor Server app's AuthorizeView component, but the content is never displayed.
[Authorize]
attribute
The [Authorize]
attribute is available in Razor components:
@page "/"
@attribute [Authorize]
You can only see this if you're signed in.
Important
Only use [Authorize]
on @page
components reached via the Blazor Router. Authorization is only performed as an aspect of routing and not for child components rendered within a page. To authorize the display of specific parts within a page, use AuthorizeView instead.
The [Authorize]
attribute also supports role-based or policy-based authorization. For role-based authorization, use the Roles parameter:
@page "/"
@attribute [Authorize(Roles = "Admin, Superuser")]
<p>You can only see this if you're in the 'Admin' or 'Superuser' role.</p>
For policy-based authorization, use the Policy parameter:
@page "/"
@attribute [Authorize(Policy = "Over21")]
<p>You can only see this if you satisfy the 'Over21' policy.</p>
If neither Roles nor Policy is specified, [Authorize]
uses the default policy:
- Authenticated (signed-in) users are authorized.
- Unauthenticated (signed-out) users are unauthorized.
When the user isn't authorized and if the app doesn't customize unauthorized content with the Router component, the framework automatically displays the following fallback message:
Not authorized.
Resource authorization
To authorize users for resources, pass the request's route data to the Resource parameter of AuthorizeRouteView.
In the Router.Found content for a requested route in the App
component (App.razor
):
<AuthorizeRouteView Resource="@routeData" RouteData="@routeData"
DefaultLayout="@typeof(MainLayout)" />
For more information on how authorization state data is passed and used in procedural logic, see the Expose the authentication state as a cascading parameter section.
When the AuthorizeRouteView receives the route data for the resource, authorization policies have access to RouteData.PageType and RouteData.RouteValues that permit custom logic to make authorization decisions.
In the following example, an EditUser
policy is created in AuthorizationOptions for the app's authorization service configuration (AddAuthorizationCore) with the following logic:
- Determine if a route value exists with a key of
id
. If the key exists, the route value is stored invalue
. - In a variable named
id
, storevalue
as a string or set an empty string value (string.Empty
). - If
id
isn't an empty string, assert that the policy is satisfied (returntrue
) if the string's value starts withEMP
. Otherwise, assert that the policy fails (returnfalse
).
In either Program.cs
or Startup.cs
(depending on the hosting model and framework version):
Add namespaces for Microsoft.AspNetCore.Components and System.Linq:
using Microsoft.AspNetCore.Components; using System.Linq;
Add the policy:
options.AddPolicy("EditUser", policy => policy.RequireAssertion(context => { if (context.Resource is RouteData rd) { var routeValue = rd.RouteValues.TryGetValue("id", out var value); var id = Convert.ToString(value, System.Globalization.CultureInfo.InvariantCulture) ?? string.Empty; if (!string.IsNullOrEmpty(id)) { return id.StartsWith("EMP", StringComparison.InvariantCulture); } } return false; }) );
The preceding example is an oversimplified authorization policy, merely used to demonstrate the concept with a working example. For more information on creating and configuring authorization policies, see Policy-based authorization in ASP.NET Core.
In the following EditUser
component, the resource at /users/{id}/edit
has a route parameter for the user's identifier ({id}
). The component uses the preceding EditUser
authorization policy to determine if the route value for id
starts with EMP
. If id
starts with EMP
, the policy succeeds and access to the component is authorized. If id
starts with a value other than EMP
or if id
is an empty string, the policy fails, and the component doesn't load.
Pages/EditUser.razor
:
@page "/users/{id}/edit"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "EditUser")]
<h1>Edit User</h1>
<p>The "EditUser" policy is satisfied! <code>Id</code> starts with 'EMP'.</p>
@code {
[Parameter]
public string? Id { get; set; }
}
@page "/users/{id}/edit"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "EditUser")]
<h1>Edit User</h1>
<p>The "EditUser" policy is satisfied! <code>Id</code> starts with 'EMP'.</p>
@code {
[Parameter]
public string Id { get; set; }
}
Customize unauthorized content with the Router component
The Router component, in conjunction with the AuthorizeRouteView component, allows the app to specify custom content if:
- The user fails an
[Authorize]
condition applied to the component. The markup of the<NotAuthorized>
element is displayed. The[Authorize]
attribute is covered in the[Authorize]
attribute section. - Asynchronous authorization is in progress, which usually means that the process of authenticating the user is in progress. The markup of the
<Authorizing>
element is displayed. - Content isn't found. The markup of the
<NotFound>
element is displayed.
In the App
component (App.razor
):
<CascadingAuthenticationState>
<Router ...>
<Found ...>
<AuthorizeRouteView ...>
<NotAuthorized>
...
</NotAuthorized>
<Authorizing>
...
</Authorizing>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView ...>
...
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
The content of <NotFound>
, <NotAuthorized>
, and <Authorizing>
tags can include arbitrary items, such as other interactive components.
If the <NotAuthorized>
tag isn't specified, the AuthorizeRouteView uses the following fallback message:
Not authorized.
An app created from the Blazor WebAssembly project template with authentication enabled includes a RedirectToLogin
component (Shared/RedirectToLogin.razor
reference source), which is positioned in the <NotAuthorized>
content of the Blazor Router in the template's App
component (reference source). When a user isn't authenticated (context.User.Identity?.IsAuthenticated != true
), the RedirectToLogin
component redirects the browser to the authentication/login
endpoint for authentication. The user is returned to the requested URL after authenticating with the identity provider.
Note
Documentation links to .NET reference source usually load the repository's default branch, which represents the current development for the next release of .NET. To select a tag for a specific release, use the Switch branches or tags dropdown list. For more information, see How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205).
Procedural logic
If the app is required to check authorization rules as part of procedural logic, use a cascaded parameter of type Task<
AuthenticationState>
to obtain the user's ClaimsPrincipal. Task<
AuthenticationState>
can be combined with other services, such as IAuthorizationService
, to evaluate policies.
In the following example:
- The
user.Identity.IsAuthenticated
executes code for authenticated (signed-in) users. - The
user.IsInRole("admin")
executes code for users in the 'Admin' role. - The
(await AuthorizationService.AuthorizeAsync(user, "content-editor")).Succeeded
executes code for users satisfying the 'content-editor' policy.
A Blazor Server app includes the appropriate namespaces by default when created from the Blazor Server project template. In a Blazor WebAssembly app, confirm the presence of the Microsoft.AspNetCore.Authorization and Microsoft.AspNetCore.Components.Authorization namespaces either in the component or in the app's _Imports.razor
file:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
Pages/ProceduralLogic.razor
:
@page "/procedural-logic"
@inject IAuthorizationService AuthorizationService
<h1>Procedural Logic Example</h1>
<button @onclick="@DoSomething">Do something important</button>
@code {
[CascadingParameter]
private Task<AuthenticationState>? authenticationState { get; set; }
private async Task DoSomething()
{
if (authenticationState is not null)
{
var authState = await authenticationState;
var user = authState?.User;
if (user is not null)
{
if (user.Identity is not null && user.Identity.IsAuthenticated)
{
// ...
}
if (user.IsInRole("Admin"))
{
// ...
}
if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
.Succeeded)
{
// ...
}
}
}
}
}
@page "/procedural-logic"
@inject IAuthorizationService AuthorizationService
<h1>Procedural Logic Example</h1>
<button @onclick="@DoSomething">Do something important</button>
@code {
[CascadingParameter]
private Task<AuthenticationState> authenticationStateTask { get; set; }
private async Task DoSomething()
{
var user = (await authenticationStateTask).User;
if (user.Identity.IsAuthenticated)
{
// ...
}
if (user.IsInRole("Admin"))
{
// ...
}
if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
.Succeeded)
{
// ...
}
}
}
Troubleshoot errors
Common errors:
Authorization requires a cascading parameter of type
Task<AuthenticationState>
. Consider usingCascadingAuthenticationState
to supply this.null
value is received forauthenticationStateTask
It's likely that the project wasn't created using a Blazor Server template with authentication enabled. Wrap a <CascadingAuthenticationState>
around some part of the UI tree, for example in the App
component (App.razor
) as follows:
<CascadingAuthenticationState>
<Router ...>
...
</Router>
</CascadingAuthenticationState>
The CascadingAuthenticationState supplies the Task<
AuthenticationState>
cascading parameter, which in turn it receives from the underlying AuthenticationStateProvider dependency injection service.
Additional resources
- Microsoft identity platform documentation
- ASP.NET Core security topics
- Configure Windows Authentication in ASP.NET Core
- Build a custom version of the Authentication.MSAL JavaScript library
- Awesome Blazor: Authentication community sample links
- ASP.NET Core Blazor Hybrid authentication and authorization
- Microsoft identity platform documentation
- ASP.NET Core security topics
- Configure Windows Authentication in ASP.NET Core
- Build a custom version of the Authentication.MSAL JavaScript library
- Awesome Blazor: Authentication community sample links
Feedback
Submit and view feedback for