Summary
A critical Authentication-Authorization Loop was identified in a .NET 10 Blazor Web App using InteractiveServer render mode. Users navigating to the /Account/Login route experienced a “flicker” effect where the login page would render briefly before being forcibly redirected or disappearing. This issue stems from a fundamental mismatch between Static SSR (Server-Side Rendering) identity endpoints and Interactive Blazor routing logic.
Root Cause
The failure is caused by a Race Condition between the ASP.NET Core Identity middleware and the Blazor Router’s authorization logic:
- The Prerendering Conflict: By default, Blazor components undergo Prerendering. During this phase, the server renders the HTML statically. The page correctly identifies the user is unauthenticated and renders the
[AllowAnonymous]login component. - Hydration vs. Authorization: Once the page “hydrates” (becomes interactive via SignalR), the Blazor Router takes control of the client-side state.
- The Loop: The
<AuthorizeRouteView>component evaluates the current user state via theCascadingAuthenticationState. Because the interactive circuit is fresh, it may briefly perceive the state as “unauthenticated” and trigger the<NotAuthorized>template. - The Redirect Trap: The
<NotAuthorized>template contains a<RedirectToLogin />component. This component forces a navigation to/Account/Login. Since the user is already on/Account/Login, the router attempts to navigate to the same route, creating a logic loop or a state mismatch that causes the component to unmount or redirect to a blank page.
Why This Happens in Real Systems
In complex distributed systems, this is a classic case of State Inconsistency between the Transport Layer and the Application Layer:
- Identity is Cookie-Based (HTTP): ASP.NET Identity relies on HTTP Cookies, which are handled by the web server’s middleware.
- Blazor is Connection-Based (SignalR): Interactive Server components rely on a persistent WebSocket connection.
- The Synchronization Gap: The “Source of Truth” for authentication exists in the HTTP headers, but the Blazor Circuit manages its own internal representation of the
ClaimsPrincipal. When the circuit establishes, there is a microscopic window where the Circuit’s view of the user is being synchronized with the Middleware’s view of the user.
Real-World Impact
- Broken User Experience: Users are physically unable to log in because the UI elements they need to interact with (input fields, submit buttons) are unmounted by the router before they can be used.
- Increased Server Load: Rapid-fire redirection loops consume CPU cycles and SignalR connection bandwidth.
- Security Confusion: Developers often mistake this for a session/cookie issue, leading them to spend hours debugging JWTs or Cookie expiration when the issue is actually Client-side Routing.
Example or Code
To fix this, the <NotAuthorized> logic must explicitly ignore the login route to prevent the redirect loop.
@if (NavigationManager.Uri != NavigationManager.BaseUri + "Account/Login")
{
}
else
{
You are not authorized to access this resource.
}
Not found
@code {
[Inject]
private NavigationManager NavigationManager { get; set; } = default!;
}
How Senior Engineers Fix It
Senior engineers look beyond the immediate symptom and address the Architectural Pattern:
- Route Exclusion: They implement logic within the
AuthorizeRouteViewto ensure that if the current URI matches the login path, theNotAuthorizedredirection logic is bypassed. - Hybrid Rendering Strategy: Instead of making the entire app Interactive Server, they use Static SSR for Identity/Account pages and Interactive modes only for the actual application dashboard. This ensures authentication flows through standard HTTP POST/Redirect cycles, which are more robust.
- State Synchronization: They ensure that
AuthenticationStateProvideris correctly implemented to bridge the gap between the initial HTTP request and the subsequent SignalR circuit.
Why Juniors Miss It
- Focusing on the Wrong Layer: Juniors often assume the problem is with the Identity Configuration (e.g.,
AddIdentityCore) or Cookie Settings, rather than the UI Routing logic. - Over-reliance on Interactivity: They tend to enable
InteractiveServerglobally, not realizing that certain parts of an application (like Auth/Login) are inherently better suited for Static SSR. - Missing the “Hydration” Concept: They view the page as a single static entity, whereas senior engineers view it as a two-stage process: Static HTML followed by Active SignalR Circuit.