Search code examples
c#asp.net-coreblazorblazor-server-sideblazor-client-side

Blazor Custom Authentication Provider Error


I am creating a Blazor UI application to talk to an API. Currently, I am attempting to get a custom provider for this working and I am getting a few errors.

This is the customer AuthenticationStateProvider

public class APIAuthenticationStateProvider : AuthenticationStateProvider
{
    private readonly HttpClient _httpClient;
    private readonly ILocalStorageService _localStorage;
    public APIAuthenticationStateProvider(HttpClient httpClient, ILocalStorageService localStorage)
    {
        _httpClient = httpClient;
        _localStorage = localStorage;
    }
    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var token = await _localStorage.GetItemAsync<string>("authToken");

        if (string.IsNullOrWhiteSpace(token))
        {
            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
        }

        _httpClient.DefaultRequestHeaders.Authorization =
            new AuthenticationHeaderValue("bearer", token);

        var claims = ParseClaims(token);

        return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(claims,"jwt")));
    }
}

My Configure Services function in Startup.cs file looks like this

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
    services.AddServerSideBlazor();
    services.AddBlazoredLocalStorage();
    services.AddScoped<AuthenticationStateProvider, APIAuthenticationStateProvider>();
    services.AddTransient<IAuthRepository, AuthRepository>();
    services.AddHttpClient();
}

When I executed I get the following exception

InvalidOperationException: JavaScript interop calls cannot be issued at this time. This is because the component is being statically rendererd. When prerendering is enabled, JavaScript interop calls can only be performed during the OnAfterRenderAsync lifecycle method.

Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSRuntime.BeginInvokeJS(long asyncHandle, string identifier, string argsJson)
Microsoft.JSInterop.JSRuntime.InvokeAsync<TValue>(string identifier, CancellationToken cancellationToken, object[] args)
Microsoft.JSInterop.JSRuntime.InvokeWithDefaultCancellation<T>(string identifier, object[] args)
System.Threading.Tasks.ValueTask<TResult>.get_Result()
System.Runtime.CompilerServices.ValueTaskAwaiter<TResult>.GetResult()
Blazored.LocalStorage.LocalStorageService.GetItemAsync<T>(string key)
BookStore_UI.Providers.APIAuthenticationStateProvider.GetAuthenticationStateAsync() in APIAuthenticationStateProvider.cs

I am not sure if the error is being clear and that is where the error really is, or if there is some other underlying step that I am missing. I think it might have to do with the use of Local Storage.


Solution

  • The Error had to do with the fact that the JS code was being triggered before all resources were loaded...in a nutshell.

    To stop it from crashing, I wrapped the Task GetAuthenticationStateAsync() function all in a try...catch and didn't throw an exception.