
dotnet-blazor-auth
Adding auth to Blazor. AuthorizeView, CascadingAuthenticationState, Identity UI, per-model flows.
- Installs
- 85
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-blazor-auth- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads dotnet-blazor-auth automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
dotnet-blazor-auth
Authentication and authorization across all Blazor hosting models. Covers AuthorizeView, CascadingAuthenticationState, Identity UI scaffolding, role/policy-based authorization, per-hosting-model auth flow differences (cookie vs token), and external identity providers.
Scope boundary: This skill owns Blazor-specific auth UI patterns -- AuthorizeView, CascadingAuthenticationState, Identity UI scaffolding, client-side token handling, and per-hosting-model auth flow configuration. API-level auth (JWT, OAuth/OIDC, passkeys, CORS, rate limiting) -- see [skill:dotnet-api-security].
Out of scope: JWT token generation and validation -- see [skill:dotnet-api-security]. OWASP security principles -- see [skill:dotnet-security-owasp]. bUnit testing of auth components -- see [skill:dotnet-blazor-testing]. E2E auth testing -- see [skill:dotnet-playwright]. UI framework selection -- see [skill:dotnet-ui-chooser].
Cross-references: [skill:dotnet-api-security] for API-level auth, [skill:dotnet-security-owasp] for OWASP principles, [skill:dotnet-blazor-patterns] for hosting models, [skill:dotnet-blazor-components] for component architecture, [skill:dotnet-blazor-testing] for bUnit testing, [skill:dotnet-playwright] for E2E testing, [skill:dotnet-ui-chooser] for framework selection.
Auth Flow per Hosting Model
Authentication patterns differ significantly across Blazor hosting models:
| Concern | InteractiveServer | InteractiveWebAssembly | InteractiveAuto | Static SSR | Hybrid |
|---|---|---|---|---|---|
| Auth mechanism | Cookie-based (server-side) | Token-based (JWT/OIDC) | Cookie (Server phase), Token (WASM phase) | Cookie-based (standard ASP.NET Core) | Platform-native or cookie |
| User state access | Direct HttpContext access | AuthenticationStateProvider | Varies by phase | HttpContext | Platform auth APIs |
| Token storage | Not needed (cookie) | localStorage or sessionStorage | Transition from cookie to token | Not needed (cookie) | Secure storage (Keychain, etc.) |
| Refresh handling | Circuit reconnection | Token refresh via interceptor | Automatic | Standard cookie renewal | Platform-specific |
InteractiveServer Auth
Server-side Blazor uses cookie authentication. The user authenticates via a standard ASP.NET Core login flow, and the cookie is sent with the initial HTTP request that establishes the SignalR circuit.
// Program.cs
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Account/Login";
options.AccessDeniedPath = "/Account/AccessDenied";
});
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddAuthorization();
Gotcha: HttpContext is available during the initial HTTP request but is null inside interactive components after the SignalR circuit is established. Do not access HttpContext in interactive component lifecycle methods. Use AuthenticationStateProvider instead.
InteractiveWebAssembly Auth
WASM runs in the browser. Cookie auth works for same-origin APIs (and Backend-for-Frontend / BFF patterns), but token-based auth (OIDC/JWT) is the standard approach for cross-origin APIs and delegated access scenarios:
// Client Program.cs (WASM)
builder.Services.AddOidcAuthentication(options =>
{
options.ProviderOptions.Authority = "https://login.example.com";
options.ProviderOptions.ClientId = "blazor-wasm-client";
options.ProviderOptions.ResponseType = "code";
options.ProviderOptions.DefaultScopes.Add("api");
});
// Attach tokens to API calls using BaseAddressAuthorizationMessageHandler
// (auto-attaches tokens for requests to the app's base address)
builder.Services.AddHttpClient("API", client =>
client.BaseAddress = new Uri("https://api.example.com"))
.AddHttpMessageHandler(sp =>
sp.GetRequiredService<AuthorizationMessageHandler>()
.ConfigureHandler(
authorizedUrls: ["https://api.example.com"],
scopes: ["api"]));
builder.Services.AddScoped(sp =>
sp.GetRequiredService<IHttpClientFactory>().CreateClient("API"));
InteractiveAuto Auth
Auto mode starts as InteractiveServer (cookie auth), then transitions to WASM (token auth). Handle both:
// Server Program.cs
builder.Services.AddAuthentication()
.AddCookie()
.AddJwtBearer(); // For WASM API calls after transition
builder.Services.AddCascadingAuthenticationState();
Hybrid (MAUI) Auth
// Register platform-specific auth
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, MauiAuthStateProvider>();
// Custom provider using secure storage
public class MauiAuthStateProvider : AuthenticationStateProvider
{
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
var token = await SecureStorage.Default.GetAsync("auth_token");
if (string.IsNullOrEmpty(token))
{
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
}
var claims = ParseClaimsFromJwt(token);
var identity = new ClaimsIdentity(claims, "jwt");
return new AuthenticationState(new ClaimsPrincipal(identity));
}
}
AuthorizeView
AuthorizeView conditionally renders content based on the user's authentication and authorization state.
Basic Usage
<AuthorizeView>
<Authorized>
<p>Welcome, @context.User.Identity?.Name!</p>
<a href="/Account/Logout">Log out</a>
</Authorized>
<NotAuthorized>
<a href="/Account/Login">Log in</a>
</NotAuthorized>
<Authorizing>
<p>Checking authentication...</p>
</Authorizing>
</AuthorizeView>
Role-Based
<AuthorizeView Roles="Admin,Manager">
<Authorized>
<AdminDashboard />
</Authorized>
<NotAuthorized>
<p>You do not have access to the admin dashboard.</p>
</NotAuthorized>
</AuthorizeView>
Policy-Based
<AuthorizeView Policy="CanEditProducts">
<Authorized>
<button @onclick="EditProduct">Edit</button>
</Authorized>
</AuthorizeView>
// Register policy in Program.cs
builder.Services.AddAuthorizationBuilder()
.AddPolicy("CanEditProducts", policy =>
policy.RequireClaim("permission", "products.edit"));
CascadingAuthenticationState
CascadingAuthenticationState provides the current AuthenticationState as a cascading parameter to all descendant components.
Setup
// Program.cs -- register cascading auth state
builder.Services.AddCascadingAuthenticationState();
This replaces wrapping the entire app in <CascadingAuthenticationState> (the older pattern). The service-based registration (.NET 8+) is preferred.
Consuming Auth State in Components
@code {
[CascadingParameter]
private Task<AuthenticationState>? AuthState { get; set; }
private string? userName;
protected override async Task OnInitializedAsync()
{
if (AuthState is not null)
{
var state = await AuthState;
userName = state.User.Identity?.Name;
}
}
}
Accessing Claims
var state = await AuthState;
var user = state.User;
// Check authentication
if (user.Identity?.IsAuthenticated == true)
{
var email = user.FindFirst(ClaimTypes.Email)?.Value;
var roles = user.FindAll(ClaimTypes.Role).Select(c => c.Value);
var isAdmin = user.IsInRole("Admin");
}
Identity UI Scaffolding
ASP.NET Core Identity provides a complete authentication system with registration, login, email confirmation, password reset, and two-factor authentication.
Adding Identity to a Blazor Web App
# Add Identity scaffolding
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.AspNetCore.Identity.UI
// Program.cs
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = true;
options.SignIn.RequireConfirmedAccount = true;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
Scaffolding Identity Pages
# Scaffold individual Identity pages for customization
dotnet aspnet-codegenerator identity -dc ApplicationDbContext --files "Account.Login;Account.Register;Account.Logout"
Custom Identity UI with Blazor Components
For a fully Blazor-native auth experience, create Blazor components that call Identity APIs:
@page "/Account/Login"
@inject SignInManager<ApplicationUser> SignInManager
@inject NavigationManager Navigation
<EditForm Model="loginModel" OnValidSubmit="HandleLogin" FormName="login" Enhance>
<DataAnnotationsValidator />
<ValidationSummary />
<div>
<InputText @bind-Value="loginModel.Email" placeholder="Email" />
</div>
<div>
<InputText @bind-Value="loginModel.Password" type="password" placeholder="Password" />
</div>
<div>
<InputCheckbox @bind-Value="loginModel.RememberMe" /> Remember me
</div>
<button type="submit">Log in</button>
</EditForm>
@if (!string.IsNullOrEmpty(errorMessage))
{
<p class="text-danger">@errorMessage</p>
}
@code {
[SupplyParameterFromForm]
private LoginModel loginModel { get; set; } = new();
private string? errorMessage;
private async Task HandleLogin()
{
var result = await SignInManager.PasswordSignInAsync(
loginModel.Email, loginModel.Password,
loginModel.RememberMe, lockoutOnFailure: true);
if (result.Succeeded)
{
Navigation.NavigateTo("/", forceLoad: true);
}
else if (result.RequiresTwoFactor)
{
Navigation.NavigateTo("/Account/LoginWith2fa");
}
else if (result.IsLockedOut)
{
errorMessage = "Account is locked. Try again later.";
}
else
{
errorMessage = "Invalid login attempt.";
}
}
}
Gotcha: SignInManager uses HttpContext to set cookies. In Interactive render modes, HttpContext is not available after the circuit is established. Login/logout pages must use Static SSR (no @rendermode) so they have access to HttpContext for cookie operations.
Role and Policy-Based Authorization
Page-Level Authorization
@page "/admin"
@attribute [Authorize(Roles = "Admin")]
<h1>Admin Panel</h1>
@page "/products/manage"
@attribute [Authorize(Policy = "ProductManager")]
<h1>Manage Products</h1>
Defining Policies
builder.Services.AddAuthorizationBuilder()
.AddPolicy("ProductManager", policy =>
policy.RequireRole("Admin", "ProductManager"))
.AddPolicy("CanDeleteOrders", policy =>
policy.RequireClaim("permission", "orders.delete")
.RequireAuthenticatedUser())
.AddPolicy("MinimumAge", policy =>
policy.AddRequirements(new MinimumAgeRequirement(18)));
Custom Authorization Handler
public sealed class MinimumAgeRequirement(int minimumAge) : IAuthorizationRequirement
{
public int MinimumAge { get; } = minimumAge;
}
public sealed class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
MinimumAgeRequirement requirement)
{
var dateOfBirthClaim = context.User.FindFirst("date_of_birth");
if (dateOfBirthClaim is not null
&& DateOnly.TryParse(dateOfBirthClaim.Value, out var dob))
{
var age = DateOnly.FromDateTime(DateTime.UtcNow).Year - dob.Year;
if (age >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
}
return Task.CompletedTask;
}
}
// Register
builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
Procedural Authorization in Components
@inject IAuthorizationService AuthorizationService
@code {
[CascadingParameter]
private Task<AuthenticationState>? AuthState { get; set; }
private bool canEdit;
protected override async Task OnInitializedAsync()
{
if (AuthState is not null)
{
var state = await AuthState;
var result = await AuthorizationService.AuthorizeAsync(
state.User, "CanEditProducts");
canEdit = result.Succeeded;
}
}
}
External Identity Providers
Adding External Providers
builder.Services.AddAuthentication()
.AddMicrosoftAccount(options =>
{
options.ClientId = builder.Configuration["Auth:Microsoft:ClientId"]!;
options.ClientSecret = builder.Configuration["Auth:Microsoft:ClientSecret"]!;
})
.AddGoogle(options =>
{
options.ClientId = builder.Configuration["Auth:Google:ClientId"]!;
options.ClientSecret = builder.Configuration["Auth:Google:ClientSecret"]!;
});
External Login Flow per Hosting Model
| Hosting Model | Flow | Notes |
|---|---|---|
| InteractiveServer / Static SSR | Standard OAuth redirect (server-side) | Cookie stored after callback |
| InteractiveWebAssembly | OIDC with PKCE (client-side) | Token stored in browser |
| Hybrid (MAUI) | WebAuthenticator or MSAL | Platform-specific secure storage |
For WASM, configure the OIDC provider in the client project:
// Client Program.cs
builder.Services.AddOidcAuthentication(options =>
{
options.ProviderOptions.Authority = "https://login.microsoftonline.com/{tenant}";
options.ProviderOptions.ClientId = "{client-id}";
options.ProviderOptions.ResponseType = "code";
});
For MAUI Hybrid:
var result = await WebAuthenticator.Default.AuthenticateAsync(
new Uri("https://login.example.com/authorize"),
new Uri("myapp://callback"));
var token = result.AccessToken;
Agent Gotchas
- Do not access
HttpContextin interactive components.HttpContextis only available during the initial HTTP request. After the SignalR circuit is established (InteractiveServer) or the WASM runtime loads, it isnull. UseAuthenticationStateProviderorCascadingAuthenticationStateinstead. - Do not rely on cookies for cross-origin or delegated API access in WASM. Use OIDC/JWT with
AuthorizationMessageHandlerfor cross-origin APIs. Same-origin and Backend-for-Frontend (BFF) cookie auth remains valid for WASM apps. - Do not render login/logout pages in Interactive mode.
SignInManagerrequiresHttpContextto set/clear cookies. Login and logout pages must use Static SSR render mode. - Do not store tokens in
localStoragewithout considering XSS. If the app is vulnerable to XSS, tokens inlocalStoragecan be stolen. UsesessionStorage(cleared on tab close) or the OIDC library's built-in storage mechanisms with PKCE. - Do not forget
AddCascadingAuthenticationState(). Without it,[CascadingParameter] Task<AuthenticationState>is alwaysnullin components, silently breaking auth checks. - Do not use
AddIdentityandAddDefaultIdentitytogether.AddDefaultIdentityincludes UI scaffolding;AddIdentitydoes not. Choose one based on whether you want the default Identity UI pages.
Prerequisites
- .NET 8.0+ (Blazor Web App with render modes,
AddCascadingAuthenticationStateservice registration) Microsoft.AspNetCore.Identity.EntityFrameworkCorefor Identity with EF CoreMicrosoft.AspNetCore.Identity.UIfor default Identity UI scaffoldingMicrosoft.AspNetCore.Authentication.MicrosoftAccount/.Googlefor external providersMicrosoft.Authentication.WebAssembly.Msalfor WASM with Microsoft Identity (Azure AD/Entra)
References
FAQ
What does the dotnet-blazor-auth skill do?
Adding auth to Blazor. AuthorizeView, CascadingAuthenticationState, Identity UI, per-model flows.
How do I install dotnet-blazor-auth?
Run npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-blazor-auth in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/dotnet-blazor-auth/ (personal) or .claude/skills/dotnet-blazor-auth/ (project).
Which AI agents can use dotnet-blazor-auth?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is dotnet-blazor-auth safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains dotnet-blazor-auth?
It is published by wshaddix in wshaddix/dotnet-skills. It has 85 recorded installs.
More from wshaddix/dotnet-skills
dotnet-xunit
wshaddix/dotnet-skills
Writing xUnit tests. v3 Fact/Theory, fixtures, parallelism, IAsyncLifetime, v2 compatibility.
dotnet-testing-strategy
wshaddix/dotnet-skills
Deciding how to test .NET code. Unit vs integration vs E2E decision tree, test doubles.
modern-csharp-coding-standards
wshaddix/dotnet-skills
Write modern, high-performance C code using records, pattern matching, value objects, async/await, Span /Memory , and best-practice API design patterns. Emphasizes functional-style programming with C 12+ features. Use when writing new C code or refactoring existing code, designing public APIs for libraries or services, optimizing performance-critical code paths, or building async/await-heavy applications.
csharp-wolverinefx
wshaddix/dotnet-skills
Build .NET applications with WolverineFX for messaging, HTTP services, and event sourcing. Use when implementing command handlers, message handlers, HTTP endpoints with WolverineFx.HTTP, transactional outbox patterns, event sourcing with Marten, CQRS architectures, cascading messages, batch message processing, or configuring transports like RabbitMQ, Azure Service Bus, or Amazon SQS.
testcontainers
wshaddix/dotnet-skills
Patterns for using Testcontainers in .NET integration tests to spin up real dependencies like databases and message queues. Use when writing integration tests that require real databases, testing with message brokers like RabbitMQ or Kafka, or isolating test dependencies with Docker containers.
microsoft-extensions-dependency-injection
wshaddix/dotnet-skills
Dependency injection patterns and best practices using Microsoft.Extensions.DependencyInjection for .NET applications. Use when configuring DI containers in .NET, choosing between service lifetimes (Singleton, Scoped, Transient), or implementing decorator patterns and service interception.
Popular backend & apis skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
entra-app-registration
microsoft/azure-skills
Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.
google-agents-cli-adk-code
google/agents-cli
This skill should be used when the user wants to "write agent code", "build an agent with ADK", "add a tool", "create a callback", "define an agent", "use state management" — in a project that needs ADK (Agent Development Kit) API patterns and code examples. It provides a quick reference for agent types, tool definitions, orchestration patterns, callbacks, state management, the graph Workflow API, and reference recipes to study. Do NOT use for scaffolding (use google-agents-cli-scaffold) or deployment (use google-agents-cli-deploy).
embedded-captions
heygen-com/hyperframes
Add captions or subtitles to an existing single-subject talking-head video without editing the footage. Use for plain verbatim captions, cinematic captions embedded behind the subject, VFX captions, “炸/特效/酷炫字幕,” or a named identity from the 35-style catalog. Route by visual identity, not by backend engine. The quiet anchor rail is the default; embed every word only when the user explicitly wants a fully cinematic treatment. The workflow runs locally end to end, including transcription and subject matting; split multi-shot footage before applying it.
entra-agent-id
microsoft/azure-skills
Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmipath, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmipath token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry).
neon
neondatabase/agent-skills
Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child skill neon-postgres wins for an existing DATABASEURL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Child skill neon-realtime wins for live queries in reactive apps and agents. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, realtime, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.