5

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?

11
  • 1
    IHttpContextAccessor should not be used with Blazor. I suggest you read about this matter. Github issue, Doc Commented Oct 20, 2022 at 8:40
  • @T.Trassoudaine Thanks, yeah I need to know about other alternative way to check whether application is in prerender mode or not Commented Oct 20, 2022 at 8:45
  • I think this is more the context in which you are calling this than checking for prerendering. You should do it in OnAfterRenderAsync() for example. Commented Oct 20, 2022 at 8:51
  • I have seen this solution to use OnAfterRenderAsync() but not sure how to do it Commented Oct 20, 2022 at 8:59
  • Where is AuthStateProvider.GetAuthenticationStateAsync called ? Commented Oct 20, 2022 at 9:45

1 Answer 1

3

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

Sign up to request clarification or add additional context in comments.

1 Comment

Yes, I've used the same work-around. Another issue with this...the user information getting load lately after application rendered. So, not a good user experience.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.