Divyang Desai
Divyang Desai

Reputation: 7866

How to handle authentication in blazor application with prerendering enabled

I trying to implement token base authentication in Blazor webassembly web application with Prerendering enabled.

The steps I have done so far:

  1. Created a sample Blazor Webassembly application
  2. Followed the Official MS doc: Prerender and integrate ASP.NET Core Razor components
  3. Checked if application works
  4. Added token base authentication (custom) changes - ref.

It gives an error at AuthStateProvider

public class AuthStateProvider : AuthenticationStateProvider
{
    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {       
        var token = await _localStorage.GetItemAsync<string>("authToken");
        if (string.IsNullOrWhiteSpace(token))
            return _anonymous;

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

        return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(JwtParser.ParseClaimsFromJwt(token), "jwtAuthType")));
        
        return _anonymous;
    }
}

It gives an error

InvalidOperationException: JavaScript interop calls cannot be issued during server-side prerendering, because the page has not yet loaded in the browser. Prerendered components must wrap any JavaScript interop calls in conditional logic to ensure those interop calls are not attempted during prerendering.

at this line

var token = await _localStorage.GetItemAsync<string>("authToken");

Now that is obvious; this line should be wrapped in a condition to check for prerendering like:

public class AuthStateProvider : AuthenticationStateProvider
{
    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {   
        var isNotPreRendering = this._httpContextAccessor.HttpContext.Response.HasStarted;    
        
        if(isNotPreRendering)
        {
            var token = await _localStorage.GetItemAsync<string>("authToken");
            if (string.IsNullOrWhiteSpace(token))
                return _anonymous;
    
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
    
            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(JwtParser.ParseClaimsFromJwt(token), "jwtAuthType")));
        }
        
        return _anonymous;
    }
}

But the value of isNotPreRendering always false. Is there any other way or work around to make it work?

Upvotes: 5

Views: 1665

Answers (1)

Jesus Fortuna
Jesus Fortuna

Reputation: 164

I have fixed this issue in this way:

  1. Once the app hits GetAuthenticationStateAsync() will find a try-catch, withing the catch I will return an AnonymousState.

         AuthenticationState anonymousState = new(new ClaimsPrincipal(new ClaimsIdentity()));
    
         try
         {
             var token = await _localStorageService.GetItemAsync<string>("authToken");
             var memberId = await _localStorageService.GetItemAsync<int>("memberId");
    
             if (string.IsNullOrEmpty(token) || memberId == 0)
                 return anonymousState;
    
             _httpClient.DefaultRequestHeaders.Authorization = new BasicAuthenticationHeaderValue("bearer", token);
    
             var authState = new AuthenticationState(
                 new ClaimsPrincipal(
                     new ClaimsIdentity(JwtParser.ParseClaimFromJwt(token), "jwtAuthType")));
    
             NotifyAuthenticationStateChanged(Task.FromResult(authState));
    
             return authState;
         }
         catch
         {
             return await Task.FromResult(anonymousState);
         }
    
  2. In my MainLayout.cs I call the AuthenticationState again. This is not the cleanest solution but it does the work

Upvotes: 3

Related Questions