$npx -y skills add wshaddix/dotnet-skills --skill dotnet-blazor-authAdding auth to Blazor. AuthorizeView, CascadingAuthenticationState, Identity UI, per-model flows.
| 1 | # dotnet-blazor-auth |
| 2 | |
| 3 | 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. |
| 4 | |
| 5 | **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]. |
| 6 | |
| 7 | **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]. |
| 8 | |
| 9 | 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. |
| 10 | |
| 11 | --- |
| 12 | |
| 13 | ## Auth Flow per Hosting Model |
| 14 | |
| 15 | Authentication patterns differ significantly across Blazor hosting models: |
| 16 | |
| 17 | | Concern | InteractiveServer | InteractiveWebAssembly | InteractiveAuto | Static SSR | Hybrid | |
| 18 | |---|---|---|---|---|---| |
| 19 | | 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 | |
| 20 | | User state access | Direct `HttpContext` access | `AuthenticationStateProvider` | Varies by phase | `HttpContext` | Platform auth APIs | |
| 21 | | Token storage | Not needed (cookie) | `localStorage` or `sessionStorage` | Transition from cookie to token | Not needed (cookie) | Secure storage (Keychain, etc.) | |
| 22 | | Refresh handling | Circuit reconnection | Token refresh via interceptor | Automatic | Standard cookie renewal | Platform-specific | |
| 23 | |
| 24 | ### InteractiveServer Auth |
| 25 | |
| 26 | 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. |
| 27 | |
| 28 | ```csharp |
| 29 | // Program.cs |
| 30 | builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) |
| 31 | .AddCookie(options => |
| 32 | { |
| 33 | options.LoginPath = "/Account/Login"; |
| 34 | options.AccessDeniedPath = "/Account/AccessDenied"; |
| 35 | }); |
| 36 | |
| 37 | builder.Services.AddCascadingAuthenticationState(); |
| 38 | builder.Services.AddAuthorization(); |
| 39 | ``` |
| 40 | |
| 41 | **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. |
| 42 | |
| 43 | ### InteractiveWebAssembly Auth |
| 44 | |
| 45 | 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: |
| 46 | |
| 47 | ```csharp |
| 48 | // Client Program.cs (WASM) |
| 49 | builder.Services.AddOidcAuthentication(options => |
| 50 | { |
| 51 | options.ProviderOptions.Authority = "https://login.example.com"; |
| 52 | options.ProviderOptions.ClientId = "blazor-wasm-client"; |
| 53 | options.ProviderOptions.ResponseType = "code"; |
| 54 | options.ProviderOptions.DefaultScopes.Add("api"); |
| 55 | }); |
| 56 | ``` |
| 57 | |
| 58 | ```csharp |
| 59 | // Attach tokens to API calls using BaseAddressAuthorizationMessageHandler |
| 60 | // (auto-attaches tokens for requests to the app's base address) |
| 61 | builder.Services.AddHttpClient("API", client => |
| 62 | client.BaseAddress = new Uri("https://api.example.com")) |
| 63 | .AddHttpMessageHandler(sp => |
| 64 | sp.GetRequiredService<AuthorizationMessageHandler>() |
| 65 | .ConfigureHandler( |
| 66 | authorizedUrls: ["https://api.example.com"], |
| 67 | scopes: ["api"])); |
| 68 | |
| 69 | builder.Services.AddScoped(sp => |
| 70 | sp.GetRequiredService<IHttpClientFactory>().CreateClient("API")); |
| 71 | ``` |
| 72 | |
| 73 | ### InteractiveAuto Auth |
| 74 | |
| 75 | Auto mode starts as InteractiveServer (cookie auth), then transitions to WASM (token auth). Handle both: |
| 76 | |
| 77 | ```csharp |
| 78 | // Server Program.cs |
| 79 | builder.Services.AddAuthentication() |
| 80 | .AddCookie() |
| 81 | .AddJwtBearer(); // For WASM API calls after transition |
| 82 | |
| 83 | builder.Services.AddCascadingAuthenticationState(); |
| 84 | ``` |
| 85 | |
| 86 | ### Hybrid (MAUI) Auth |
| 87 | |
| 88 | ```csharp |
| 89 | // Register platform-specific auth |
| 90 | builder.Services.AddAuthorizationCore(); |
| 91 | builder.Services.AddScoped<AuthenticationStateProvider, MauiAuthStateProvider>(); |
| 92 | |
| 93 | // Custom provider using secure storage |
| 94 | public class MauiAuthStateProvider : AuthenticationStateProvider |
| 95 | { |
| 96 | publi |