-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
Background and Motivation
In Blazor SSR applications, developers often store authentication tokens in browser-based secure storage (e.g., localStorage or sessionStorage). To retrieve these tokens, we rely on JS interop. However, AuthenticationStateProvider is invoked twice, once during server-side rendering and again after client-side hydration.
During the initial server render, JS runtime is unavailable, and any attempt to access secure storage via JS interop results in an exception. Developers must manually catch and suppress this exception, which introduces unnecessary complexity and performance overhead.
Proposed API
Option 1: Event Hooks in AuthenticationStateProvider
Introduce two virtual methods or events to distinguish invocation context:
protected virtual Task OnServerAuthInvokedAsync();
protected virtual Task OnClientAuthInvokedAsync();
These hooks would allow developers to conditionally execute logic based on rendering phase, avoiding JS interop during server render.
Option 2: Environment Flags (less desirable but helpful)
Add runtime flags to detect JS availability:
public static class Environment
{
public static bool SupportsJsRuntime { get; }
public static bool JsRuntimeAvailable { get; }
}
These flags would allow developers to safely check for JS interop support before accessing secure storage.
Usage Examples
public class CustomAuthProvider : AuthenticationStateProvider
{
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
if (Environment.SupportsJsRuntime && Environment.JsRuntimeAvailable)
{
// Safe to access secure storage
}
else
{
// Fallback logic for server-side render
}
}
protected override Task OnServerAuthInvokedAsync()
{
// Skip JS interop
}
protected override Task OnClientAuthInvokedAsync()
{
// Access secure storage
}
}
Alternative Designs
-
Using IJSRuntime.IsAvailable or similar runtime checks, but this is not currently exposed.
-
Wrapping JS interop in try-catch blocks, which is error-prone and inefficient.
Risks
-
Minimal risk if implemented as optional hooks or flags.
-
Could introduce subtle behavior changes if not clearly documented.