/configure-auth
Add authentication and authorization to a Blazor Web App, accounting for the app's render mode. USE WHEN the user needs [Authorize] on pages, AuthorizeView, role or policy-based access, login/logout Identity pages, or AuthenticationStateProvider. Also USE WHEN auth state is null
Claude Code
$ npx -y skills add dotnet/skills --skill configure-auth --agent claude-code
Codex
$ npx skills add dotnet/skills --skill configure-auth -a codex -y
Cursor
$ npx skills add dotnet/skills --skill configure-auth -a cursor -y
Gemini CLI
$ npx skills add dotnet/skills --skill configure-auth -a gemini-cli -y
GitHub Copilot
$ npx skills add dotnet/skills --skill configure-auth -a github-copilot -y
OpenCode
$ npx skills add dotnet/skills --skill configure-auth -a opencode -y
Windsurf
$ npx skills add dotnet/skills --skill configure-auth -a windsurf -y
SKILL.md
configure-auth.SKILL.mdlicense: MIT
name: configure-auth
description: >
Add authentication and authorization to a Blazor Web App, accounting for the app's render mode.
USE WHEN the user needs [Authorize] on pages, AuthorizeView, role or policy-based access,
login/logout Identity pages, or AuthenticationStateProvider.
Also USE WHEN auth state is null after WebAssembly loads, SignInManager throws in an interactive
component, NotAuthorized content never renders in static SSR, or HttpContext.User is null in
an interactive component.
DO NOT USE for general component authoring (see author-component), for prerendering concerns
unrelated to auth (see support-prerendering), or for managing non-auth cascading state
(see coordinate-components).
Configure Auth
Step 1 — Read AGENTS.md
Read `AGENTS.md` at the workspace root for the project's interactivity mode and scope before making changes.
Step 2 — Register auth services in Program.cs
// Program.cs (server project)
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddAuthorization();
For ASP.NET Core Identity add the Identity services:
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddIdentityCookies();
builder.Services.AddIdentityCore<ApplicationUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddSignInManager()
.AddDefaultTokenProviders();Step 3 — Wire App.razor for auth and render mode
The `App.razor` component must use `AuthorizeRouteView` and conditionally apply the render mode so that pages excluded from interactive routing render statically.
<!DOCTYPE html>
<html>
<head>
<HeadOutlet @rendermode="RenderModeForPage" />
</head>
<body>
<Routes @rendermode="RenderModeForPage" />
<script src="_framework/blazor.web.js"></script>
</body>
</html>
@code {
[CascadingParameter]
public HttpContext HttpContext { get; set; } = default!;
private IComponentRenderMode? RenderModeForPage =>
HttpContext.AcceptsInteractiveRouting()
? InteractiveServer // replace with the app's render mode
: null;
}In `Routes.razor` (or wherever the router lives), use `AuthorizeRouteView`:
<Router AppAssembly="typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="routeData"
DefaultLayout="typeof(Layout.MainLayout)">
<NotAuthorized>
@if (context.User.Identity?.IsAuthenticated != true)
{
<RedirectToLogin />
}
else
{
<p>You are not authorized to access this resource.</p>
}
</NotAuthorized>
</AuthorizeRouteView>
<FocusOnNavigate RouteData="routeData" Selector="h1" />
</Found>
</Router>Step 4 — Protect pages and components
[Authorize] attribute on pages
@page "/admin"
@attribute [Authorize]
With roles or policies:
@attribute [Authorize(Roles = "Admin")]
@attribute [Authorize(Policy = "RequireManager")]
AuthorizeView for conditional UI
<AuthorizeView>
<Authorized>Welcome, @context.User.Identity?.Name!</Authorized>
<NotAuthorized><a href="Account/Login">Log in</a></NotAuthorized>
</AuthorizeView>Role/policy variants:
<AuthorizeView Roles="Admin,Manager">
<Authorized>Admin content here</Authorized>
</AuthorizeView>Access auth state in code
[CascadingParameter]
private Task<AuthenticationState>? AuthState { get; set; }
protected override async Task OnInitializedAsync()
{
if (AuthState is not null)
{
var state = await AuthState;
var isAdmin = state.User.IsInRole("Admin");
}
}Step 5 — Identity pages must stay static SSR
`SignInManager` and `UserManager` use `HttpContext` internally and **throw in interactive components**. Identity pages (login, register, manage) must render as static SSR.
In a **globally interactive** app, mark every Identity page:
@page "/Account/Login"
@attribute [ExcludeFromInteractiveRouting]
This forces a full-page navigation (exits the interactive circuit) so the page renders through the static SSR pipeline with a real `HttpContext`.
`App.razor` must use `AcceptsInteractiveRouting()` (Step 3) to return `null` for these pages — otherwise the framework still tries to render them interactively.
In a **per-page** app, Identity pages are static by default (no `@rendermode` directive), so `[ExcludeFromInteractiveRouting]` is not needed.
Step 6 — Auth state in WebAssembly / Auto mode
WebAssembly components run in the browser and have no `HttpContext`. Auth state must be serialized from the server during prerendering and deserialized on the client.
**Server `Program.cs`:**
builder.Services.AddAuthenticationStateSerialization();
**Client `.Client/Program.cs`:**
builder.Services.AddAuthenticationStateDeserialization();
Without these calls, `Task<AuthenticationState>` resolves to an anonymous user after WebAssembly takes over from prerendering.
`AddAuthenticationStateSerialization` accepts options to include role and claim data:
builder.Services.AddAuthenticationStateSerialization(options =>
options.SerializeAllClaims = true);Render Mode × Auth Matrix
| Render mode | HttpContext.User | SignInManager | Auth state source | Key requirement | |---|---|---|---|---| | Static SSR | Available | Works | Server pipeline | Use middleware for redirects, `<NotAuthorized>` does NOT render | | Server (interactive) | NOT available | Throws | `CascadingAuthenticationState` | Use `[Authorize]` + `AuthorizeView`, not `HttpContext` | | WebAssembly | NOT available | Throws | Serialized f
Read more
license: MIT name: configure-auth description: > Add authentication and authorization to a Blazor Web App, accounting for the app's render mode. USE WHEN the user needs [Authorize] on pages, AuthorizeView, role or policy-based access, login/logout Identity pages, or AuthenticationStateProvider. Also USE WHEN auth state is null after WebAssembly loads, SignInManager throws in an interactive component, NotAuthorized content never renders in static SSR, or HttpContext.User is null in an interactive component. DO NOT USE for general component authoring (see author-component), for prerendering concerns unrelated to auth (see support-prerendering), or for managing non-auth cascading state (see coordinate-components).
Configure Auth
Step 1 — Read AGENTS.md
Read `AGENTS.md` at the workspace root for the project's interactivity mode and scope before making changes.
Step 2 — Register auth services in Program.cs
// Program.cs (server project) builder.Services.AddCascadingAuthenticationState(); builder.Services.AddAuthorization();
For ASP.NET Core Identity add the Identity services:
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddIdentityCookies();
builder.Services.AddIdentityCore<ApplicationUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddSignInManager()
.AddDefaultTokenProviders();Step 3 — Wire App.razor for auth and render mode
The `App.razor` component must use `AuthorizeRouteView` and conditionally apply the render mode so that pages excluded from interactive routing render statically.
<!DOCTYPE html>
<html>
<head>
<HeadOutlet @rendermode="RenderModeForPage" />
</head>
<body>
<Routes @rendermode="RenderModeForPage" />
<script src="_framework/blazor.web.js"></script>
</body>
</html>
@code {
[CascadingParameter]
public HttpContext HttpContext { get; set; } = default!;
private IComponentRenderMode? RenderModeForPage =>
HttpContext.AcceptsInteractiveRouting()
? InteractiveServer // replace with the app's render mode
: null;
}In `Routes.razor` (or wherever the router lives), use `AuthorizeRouteView`:
<Router AppAssembly="typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="routeData"
DefaultLayout="typeof(Layout.MainLayout)">
<NotAuthorized>
@if (context.User.Identity?.IsAuthenticated != true)
{
<RedirectToLogin />
}
else
{
<p>You are not authorized to access this resource.</p>
}
</NotAuthorized>
</AuthorizeRouteView>
<FocusOnNavigate RouteData="routeData" Selector="h1" />
</Found>
</Router>Step 4 — Protect pages and components
[Authorize] attribute on pages
@page "/admin" @attribute [Authorize]
With roles or policies:
@attribute [Authorize(Roles = "Admin")] @attribute [Authorize(Policy = "RequireManager")]
AuthorizeView for conditional UI
<AuthorizeView>
<Authorized>Welcome, @context.User.Identity?.Name!</Authorized>
<NotAuthorized><a href="Account/Login">Log in</a></NotAuthorized>
</AuthorizeView>Role/policy variants:
<AuthorizeView Roles="Admin,Manager">
<Authorized>Admin content here</Authorized>
</AuthorizeView>Access auth state in code
[CascadingParameter]
private Task<AuthenticationState>? AuthState { get; set; }
protected override async Task OnInitializedAsync()
{
if (AuthState is not null)
{
var state = await AuthState;
var isAdmin = state.User.IsInRole("Admin");
}
}Step 5 — Identity pages must stay static SSR
`SignInManager` and `UserManager` use `HttpContext` internally and **throw in interactive components**. Identity pages (login, register, manage) must render as static SSR.
In a **globally interactive** app, mark every Identity page:
@page "/Account/Login" @attribute [ExcludeFromInteractiveRouting]
This forces a full-page navigation (exits the interactive circuit) so the page renders through the static SSR pipeline with a real `HttpContext`.
`App.razor` must use `AcceptsInteractiveRouting()` (Step 3) to return `null` for these pages — otherwise the framework still tries to render them interactively.
In a **per-page** app, Identity pages are static by default (no `@rendermode` directive), so `[ExcludeFromInteractiveRouting]` is not needed.
Step 6 — Auth state in WebAssembly / Auto mode
WebAssembly components run in the browser and have no `HttpContext`. Auth state must be serialized from the server during prerendering and deserialized on the client.
**Server `Program.cs`:**
builder.Services.AddAuthenticationStateSerialization();
**Client `.Client/Program.cs`:**
builder.Services.AddAuthenticationStateDeserialization();
Without these calls, `Task<AuthenticationState>` resolves to an anonymous user after WebAssembly takes over from prerendering.
`AddAuthenticationStateSerialization` accepts options to include role and claim data:
builder.Services.AddAuthenticationStateSerialization(options =>
options.SerializeAllClaims = true);Render Mode × Auth Matrix
| Render mode | HttpContext.User | SignInManager | Auth state source | Key requirement | |---|---|---|---|---| | Static SSR | Available | Works | Server pipeline | Use middleware for redirects, `<NotAuthorized>` does NOT render | | Server (interactive) | NOT available | Throws | `CascadingAuthenticationState` | Use `[Authorize]` + `AuthorizeView`, not `HttpContext` | | WebAssembly | NOT available | Throws | Serialized f
This repository contains the .NET team's curated set of portable skills and host-specific custom agents for coding agents. For information about the Agent Skills standard, see agentskills.io.
Other skills on skills.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about configure-auth.
- Which coding agents can use configure-auth?
- configure-auth installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

