CtrlK
BlogDocsLog inGet started
Tessl Logo

blazor-auth-migration

Guides correct AuthenticationStateProvider registration when migrating ASP.NET Web Forms Identity/OWIN authentication to Blazor Server using scoped providers and cookie-based auth. Covers DI lifetime pitfalls (singleton vs scoped vs transient), minimal API auth endpoints, and integration with BWFC LoginView. Use when migrating authentication, fixing session bleed across browser tabs, debugging shared auth state in Playwright tests, or setting up cookie-based login and registration endpoints in a Blazor Server migration.

88

Quality

86%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

SKILL.md
Quality
Evals
Security

Context

Discovered in WingtipToys Run 7, Iteration 2. When migrating ASP.NET Web Forms applications with Identity/OWIN auth to Blazor Server, the AuthenticationStateProvider registration pattern is critical. A singleton provider shares auth state across all browser sessions — causing test interference and real-world session bleed.

Confirmed by: Run 7 acceptance tests (14/14 pass after fix). The RegisterAndLogin_EndToEnd test failed reliably with singleton registration and passed reliably with scoped + cookie auth.


⚠️ Core Rule

NEVER register AuthenticationStateProvider as a singleton in Blazor Server. Blazor Server maintains per-circuit state; singletons break this model by sharing state across all connections.


Patterns

Correct: Scoped Provider + ASP.NET Core Cookie Auth

// Program.cs — correct auth registration for Blazor Server migration
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options => options.LoginPath = "/Account/Login");
builder.Services.AddScoped<MockAuthenticationStateProvider>();
builder.Services.AddScoped<AuthenticationStateProvider>(sp =>
    sp.GetRequiredService<MockAuthenticationStateProvider>());

Why this works:

  • AddAuthentication + AddCookie gives ASP.NET Core's cookie middleware — session isolation is built-in.
  • AddScoped<MockAuthenticationStateProvider> creates one provider per Blazor circuit.
  • The factory registration (AddScoped<AuthenticationStateProvider>(sp => ...)) lets DI resolve the concrete type through the abstract base.

When to Use This Pattern

  • Mock auth during migration: When you need login/logout behavior without porting the full Identity database. Replace MockAuthenticationStateProvider with real Identity later.
  • Cookie auth for form POST endpoints: Auth forms that POST to minimal API endpoints (register, login) need HTTP cookie handling — this pattern provides it.
  • Testing: Scoped providers ensure Playwright/test browser instances don't interfere.

Anti-Patterns

❌ Singleton AuthenticationStateProvider

// WRONG — auth state shared across ALL browser sessions
builder.Services.AddSingleton<AuthenticationStateProvider, MockAuthenticationStateProvider>();

Symptoms:

  • User A logs in, User B sees authenticated state
  • Playwright tests interfere with each other (one test's login affects another)
  • Logout in one tab affects all tabs/sessions

❌ Transient AuthenticationStateProvider

// WRONG — creates a new instance per resolution, loses state within a circuit
builder.Services.AddTransient<AuthenticationStateProvider, MockAuthenticationStateProvider>();

Symptoms:

  • Auth state appears to reset randomly within a session
  • Components disagree about whether user is authenticated

Examples

Minimal API Endpoints for Auth Forms

When using cookie auth, register and login forms POST to minimal API endpoints:

// Program.cs — minimal API auth endpoints
app.MapPost("/Account/DoRegister", async (HttpContext ctx,
    MockAuthenticationStateProvider auth,
    [FromForm] string email, [FromForm] string password) =>
{
    // Register user logic here
    await auth.LoginAsync(email);
    await ctx.SignInAsync(
        CookieAuthenticationDefaults.AuthenticationScheme,
        new ClaimsPrincipal(new ClaimsIdentity(
            new[] { new Claim(ClaimTypes.Name, email) },
            CookieAuthenticationDefaults.AuthenticationScheme)));
    return Results.Redirect("/");
});

Integration with BWFC LoginView

The BWFC LoginView component wraps Blazor's <AuthorizeView> internally. It works correctly with scoped auth providers — no special configuration needed beyond the registration pattern above.

Repository
FritzAndFriends/BlazorWebFormsComponents
Last updated
Created

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.