Blazorade ID
Blazorade ID is an authentication library for Blazor applications that acquires and manages access tokens and identity tokens using the OAuth 2.0 and OpenID Connect protocols. It applies a consistent programming model across Blazor application types so authentication logic can be shared without special handling for each hosting model.
Blazorade ID is not a replacement for Microsoft's authentication stacks — it is an alternative approach for Blazor applications that want a consistent, transparent, and identity-provider-agnostic way to handle authentication.
Key Design Principles
On-Demand Token Acquisition
Tokens are obtained only when needed for a specific purpose, ensuring minimal consent prompts and scopes that match the task being performed. When an application needs a token, Blazorade ID first checks whether a valid cached token is already in the token store. If it is, the token is returned immediately. If not, Blazorade ID automatically initiates the authorization flow and acquires a token containing exactly the scopes requested.
Flexible Authorization Model
The on-demand approach supports fine-grained, task-specific authorization. Applications can offer functionality that not all users are allowed to perform without blocking those users from signing in or using other features. Instead of requiring broad consent up front, Blazorade ID requests only the scopes needed for each task at the moment they are needed.
If you prefer a more traditional application where users first log in and consent to all scopes up front, that works too — add a sign-in button with a click handler that acquires tokens with all the permissions your application needs.
Unified Programming Model
The same authentication APIs, interface contracts, and usage patterns are used across Blazor Server, Blazor WebAssembly, and .NET MAUI Blazor Hybrid. Application code does not need separate authentication logic for each hosting model. Differences in runtime characteristics, security boundaries, and storage options are handled behind stable, shared APIs through a pluggable service architecture.
When to Use Blazorade ID
Blazorade ID is a good fit when:
- You are building a Blazor-first application where authorization decisions are made in the Blazor component model.
- You want the same authentication APIs across Blazor Server, Blazor WebAssembly, and .NET MAUI Blazor Hybrid.
- You want to use
<AuthorizeView>,[Authorize], and the BlazorAuthenticationStateProviderdriven by OpenID Connect identity tokens. - You want OAuth 2.0 and OpenID Connect with Microsoft Entra ID or other compliant identity providers.
- You want on-demand, task-specific token acquisition instead of broad up-front consent.
- You need to call REST APIs using bearer token authentication.
When Not to Use Blazorade ID
Blazorade ID is intentionally scoped to Blazor applications and the Blazor component authorization model. It does not integrate with ASP.NET Core authentication middleware and does not populate HttpContext.User. Consider other options when:
- You need end-to-end ASP.NET Core authentication middleware integration, such as cookie-based sessions shared with MVC, Razor Pages, or minimal APIs.
- Your application relies primarily on request-pipeline authorization rather than Blazor component authorization.
- You are building a traditional MVC or Razor Pages application rather than a Blazor-first application.
If your application exposes server endpoints, the recommended approach is to protect those endpoints with standard bearer token validation and call them using access tokens acquired by Blazorade ID.
Getting Started
1. Install the NuGet Package
Add the Blazorade.Id NuGet package to your Blazor application.
2. Add @using Statements
Add the following @using statements to your _Imports.razor file:
@using Blazorade.Id.Services
@using Blazorade.Id.Configuration
@using Blazorade.Id.Model
@using Blazorade.Id.Components
@using Blazorade.Id.Components.Pages
3. Register Services
Register Blazorade ID services in Program.cs. The registration method depends on your application type.
Blazor Server:
builder.Services
.AddBlazoradeIdServerApplication();
Blazor WebAssembly:
builder.Services
.AddBlazoradeIdWasmApplication();
Both methods return a BlazoradeIdBuilder instance you can use to further configure Blazorade ID and register custom service implementations.
4. Configure Your Authority
Register your identity provider (IdP) as an authority. The example below reads configuration from appsettings.json:
builder.Services
.AddBlazoradeIdWasmApplication()
.AddAuthority((sp, options) =>
{
var config = sp.GetRequiredService<IConfiguration>();
config.GetRequiredSection("blazorade:id").Bind(options);
});
With a matching configuration section:
{
"blazorade": {
"id": {
"discoverydocumenturi": "https://yourtenant.ciamlogin.com/yourtenant.onmicrosoft.com/v2.0/.well-known/openid-configuration",
"clientid": "{Your application Client ID}",
"scope": "{Default scopes}",
"enablesilentauthorizationcodeflow": true
}
}
}
Important: Blazorade ID does not require any secrets in application settings. Never store client secrets or passwords in your application configuration.
Configuring Microsoft Entra ID
To register your application in Microsoft Entra ID or Microsoft Entra External ID:
- Navigate to https://entra.microsoft.com and open App registrations.
- Click New registration and give your application a name.
- In the Redirect URI section, select Single-page application (SPA) as the platform.
- Set the redirect URI to your application's root URL with
_content/Blazorade.Id/oauth-callback.htmlappended. For example:https://localhost:7890/_content/Blazorade.Id/oauth-callback.html.
Add API permissions as required by your application's needs.
Token Stores
Blazorade ID separates token storage into two stores: one for access tokens and identity tokens (ITokenStore) and one for refresh tokens (IRefreshTokenStore). This separation allows different storage and retention policies for each token type.
Access tokens and identity tokens are typically short-lived; refresh tokens can live from 24 hours up to 90 days in Microsoft Entra ID, which requires more careful handling.
Available Token Store Implementations
| Store | Type | Description |
|---|---|---|
InMemoryTokenStore |
Access/identity | Default. In-process memory only; not persisted. |
BrowserSessionStorageTokenStore |
Access/identity | Browser session storage; lives for the tab session. |
BrowserLocalStorageTokenStore |
Access/identity | Browser local storage; persists across sessions. |
NullRefreshTokenStore |
Refresh | Default. Does not store refresh tokens. |
InMemoryRefreshTokenStore |
Refresh | In-process memory; not persisted. |
BrowserSessionStorageRefreshTokenStore |
Refresh | Browser session storage. |
BrowserLocalStorageRefreshTokenStore |
Refresh | Browser local storage. |
Configure a custom token store in Program.cs:
builder.Services
.AddBlazoradeIdWasmApplication()
.AddAuthority((sp, options) =>
{
// Configure your IdP here.
})
.AddTokenStore<BrowserSessionStorageTokenStore>()
.AddRefreshTokenStore<InMemoryRefreshTokenStore>();
Security note: Any data available to the browser is potentially exposed to cross-site scripting (XSS) attacks. The longer tokens are stored and the more durable the storage, the broader the exposure window. This is why Blazorade ID does not store refresh tokens by default.
Usage Samples
Signing In and Signing Out
Blazorade ID fully supports Blazor's <AuthorizeView> component. The example below shows sign in, account switching, and sign out in a single component:
@using Microsoft.AspNetCore.Components.Authorization
@using Blazorade.Id.Services
@using Blazorade.Id.Model
@inject IAuthenticationService authService
<AuthorizeView>
<Authorized Context="authState">
<h2>Welcome @authState.User.Identity?.Name</h2>
<button @onclick="async () => await authService.SignInAsync(new SignInOptions { Prompt = Prompt.Select_Account })">
Change user
</button>
<button @onclick="async () => await authService.SignOutAsync()">
Sign out
</button>
</Authorized>
<NotAuthorized>
<button @onclick="async () => await authService.SignInAsync()">Sign in</button>
</NotAuthorized>
</AuthorizeView>
When SignOutAsync is called and Blazorade ID can resolve the end-session endpoint, the user is navigated to the IdP's end-session endpoint and returned to your application afterwards.
Getting Access Tokens and Identity Tokens
Inject ITokenService to acquire tokens for calling protected APIs:
@using Blazorade.Id.Model
@using Blazorade.Id.Services
@inject ITokenService tokenService
@code {
private async Task GetTokensAsync(Prompt? prompt = null)
{
var options = new GetTokenOptions
{
Prompt = prompt,
Scopes = ["openid", "profile", "email", "User.Read"]
};
var accessTokens = await tokenService.GetAccessTokensAsync(options);
var idToken = await tokenService.GetIdentityTokenAsync(new GetTokenOptions { Prompt = Prompt.None });
}
}
GetAccessTokensAsync returns an AccessTokenDictionary keyed by scope combinations. GetIdentityTokenAsync returns the identity token for the currently authenticated user.
Using Microsoft Graph
To call Microsoft Graph, implement a TokenCredential that wraps an access token from ITokenService:
using Azure.Core;
public class StaticTokenCredential : TokenCredential
{
public StaticTokenCredential(string token, DateTimeOffset expiresOn)
{
this.AccessToken = new AccessToken(token, expiresOn);
}
private readonly AccessToken AccessToken;
public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
=> ValueTask.FromResult(this.AccessToken);
public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
=> this.AccessToken;
}
Then use ITokenService to get an access token with the required scopes and create a GraphServiceClient:
private async Task<GraphServiceClient?> GetGraphServiceClientAsync(Prompt? prompt = null)
{
var tokens = await TokenService.GetAccessTokensAsync(new GetTokenOptions
{
Prompt = prompt,
Scopes = ["User.Read"]
});
if (tokens.Count > 0)
{
var token = tokens.First().Value;
var expires = token.GetExpirationTimeUtc() ?? DateTime.UtcNow.AddHours(1);
var credential = new StaticTokenCredential(token.RawData, expires);
return new GraphServiceClient(credential);
}
return null;
}
Services Architecture
Blazorade ID is built around a set of focused, replaceable services. All services have default implementations that work out of the box, and every service can be replaced to customize behavior for specific hosting models, identity providers, or user experience requirements.
| Service | Description |
|---|---|
ITokenService |
Central service for acquiring, refreshing, and caching tokens. The entry point for all token requests. |
IAuthenticationService |
Blazor-centric abstraction for sign-in and sign-out. Creates a ClaimsPrincipal from an identity token. |
ITokenStore |
Persists and retrieves access tokens and identity tokens. |
IRefreshTokenStore |
Persists refresh tokens for silent token renewal. |
IPropertyStore |
Stores non-token authentication state and flow-related metadata. |
IAuthorizationCodeProvider |
Initiates the PKCE authorization flow with the identity provider. |
IAuthorizationCodeProcessor |
Exchanges the authorization code for tokens at the token endpoint. |
IAuthenticationStateNotifier |
Notifies the Blazor authentication infrastructure when the current user changes. |
IAuthorizationCodeFailureNotifier |
Receives and publishes authorization flow failure events. |
IScopeAnalyzer |
Analyzes and classifies OAuth scopes for differentiated scope handling. |
IHttpRequestFactory |
Creates HttpRequestMessage instances for bearer-token-protected resources. |
IHttpService |
Thin transport abstraction for outbound HTTP communication. |
ICodeChallengeService |
Generates PKCE code verifiers and code challenges for the authorization flow. |
IRedirectUriProvider |
Supplies the redirect URI used by authentication flows. |