Skip to content

[Blazor] Improve AuthenticationStateProvider for SSR with JS-dependent secure storage #63741

@reyou

Description

@reyou

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ✔️ Resolution: AnsweredResolved because the question asked by the original author has been answered.Status: Resolvedapi-suggestionEarly API idea and discussion, it is NOT ready for implementationarea-blazorIncludes: Blazor, Razor Componentsquestion

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions