Aspnetcore: Blazor Delay in AccessToken being ready and authorized view showing

Created on 4 May 2020  路  11Comments  路  Source: dotnet/aspnetcore

Describe the bug

When making an HTTP call inside a component in the component the access token is not ready for a short time after login even when the authorized content renders. The call throws a exception however oddly enough the request still has a token attached.

blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: ''
Microsoft.AspNetCore.Components.WebAssembly.Authentication.AccessTokenNotAvailableException: ''
  at Microsoft.AspNetCore.Components.WebAssembly.Authentication.AuthorizationMessageHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x32e45d0 + 0x0030e> in <filename unknown>:0 
  at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x32cf170 + 0x0014c> in <filename unknown>:0 
  at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) <0x32e6f08 + 0x00134> in <filename unknown>:0 
  at System.Net.Http.Json.HttpClientJsonExtensions.GetFromJsonAsyncCore[T] (System.Threading.Tasks.Task`1[TResult] taskResponse, System.Text.Json.JsonSerializerOptions options, System.Threading.CancellationToken cancellationToken) <0x32f0800 + 0x000cc> in <filename unknown>:0 

To Reproduce

Make a HTTP with automatically attached access token as described in https://devblogs.microsoft.com/aspnet/blazor-webassembly-3-2-0-preview-5-release-now-available/
In the components oninit or after render method.
results in Microsoft.AspNetCore.Components.WebAssembly.Authentication.AccessTokenNotAvailableException
Refresh the page no more error.

Further technical details

  • ASP.NET Core version Blazor WASM rc1
affected-few area-blazor blazor-wasm bug investigate severity-major

Most helpful comment

Having the same issue in the GA version. Have only seen it happen on an iOS device, however.

All 11 comments

Having the same issue in the GA version. Have only seen it happen on an iOS device, however.

Same issue here, when you try to send authenticated request in the GA version in component after-render. Token is not available despite the successful authentication

Hi @javiercn , is there any update on this Issue? I am still seeing this on Blazor WASM 3.2.1

This is something @captainsafia was looking for 5.0

I am seeing this as well, is there any work around available at this time?

Ok so anyone having this issue: use a IHttpClientFactory to create the instance of the HttpClient in DI instead of trying to have the DI create the HttpClient. I have no idea why it works, but it does. Maybe something isn't getting picked up after the auth happens and an existing HttpClient cant find it?

Sounds crazy, but I just had it work. Hopefully this will help others.

Ok so anyone having this issue: use a IHttpClientFactory to create the instance of the HttpClient in DI instead of trying to have the DI create the HttpClient. I have no idea why it works, but it does. Maybe something isn't getting picked up after the auth happens and an existing HttpClient cant find it?

Sounds crazy, but I just had it work. Hopefully this will help others.

Can you provide a small snippet of what you mean please? I'm also running in to this.

Thanks!

Ok so anyone having this issue: use a IHttpClientFactory to create the instance of the HttpClient in DI instead of trying to have the DI create the HttpClient. I have no idea why it works, but it does. Maybe something isn't getting picked up after the auth happens and an existing HttpClient cant find it?
Sounds crazy, but I just had it work. Hopefully this will help others.

Can you provide a small snippet of what you mean please? I'm also running in to this.

Thanks!

Sure!

So at least for my purpose, I have service classes that call the HttpClient:

`

public class UserRetrievalService
{
    private readonly HttpClient httpClient;

    public UserService(HttpClient httpClient)
    {
        this.httpClient = httpClient;
    }

    public async Task<User> GetUser()
    {
        var result = await this.httpClient.GetFromJsonAsync<User>(@$"api/me");
        return await Task.FromResult(result );
    }
}

`

I use this in my layout once I have authenticated so I can get user data from my database (dont ask why it's not in the token). So my fix for this was this:

`

public class UserRetrievalService
{
    private readonly IHttpClientFactory httpClientFactory;

    public UserService(IHttpClientFactory httpClientFactory)
    {
        this.httpClientFactory= httpClientFactory;
    }

    public async Task<User> GetUser()
    {
        var httpClient = this.httpClientFactory.CreateClient("ServerAPI");
        var result = await httpClient.GetFromJsonAsync<User>(@$"api/me");
        return await Task.FromResult(result );
    }
}

`

So, but doing this, the HttpClient I need is created from the factory after the token is retrieved and stored in the 'BaseAddressAuthorizationMessageHandler'. Not a fan of doing this, but it works so my boss is a fan :)

Cant remember if this is what eventually solved it for me (might have been a different issue I was having). But anytime I鈥檓 using my injected HttpClient I surround the request with a try and add a catch for AccessTokenNotAvailableException. It has a method to redirect to the Identity provider to retrieve a new access token (this can happen in the background if you are already authenticated I believe).
Snippet:
try { await _api.GetAsync(Endpoint); ... } catch (AccessTokenNotAvailableException e) { e.Redirect(); }

NOTE: The redirect may not work properly if your ID provider has a different domain than your app on Safari due to Safari automatically blocking third party cookies.

Ok so anyone having this issue: use a IHttpClientFactory to create the instance of the HttpClient in DI instead of trying to have the DI create the HttpClient. I have no idea why it works, but it does. Maybe something isn't getting picked up after the auth happens and an existing HttpClient cant find it?
Sounds crazy, but I just had it work. Hopefully this will help others.

Can you provide a small snippet of what you mean please? I'm also running in to this.
Thanks!

Sure!

So at least for my purpose, I have service classes that call the HttpClient:

`

public class UserRetrievalService
{
    private readonly HttpClient httpClient;

    public UserService(HttpClient httpClient)
    {
        this.httpClient = httpClient;
    }

    public async Task<User> GetUser()
    {
        var result = await this.httpClient.GetFromJsonAsync<User>(@$"api/me");
        return await Task.FromResult(result );
    }
}

`

I use this in my layout once I have authenticated so I can get user data from my database (dont ask why it's not in the token). So my fix for this was this:

`

public class UserRetrievalService
{
    private readonly IHttpClientFactory httpClientFactory;

    public UserService(IHttpClientFactory httpClientFactory)
    {
        this.httpClientFactory= httpClientFactory;
    }

    public async Task<User> GetUser()
    {
        var httpClient = this.httpClientFactory.CreateClient("ServerAPI");
        var result = await httpClient.GetFromJsonAsync<User>(@$"api/me");
        return await Task.FromResult(result );
    }
}

`

So, but doing this, the HttpClient I need is created from the factory _after_ the token is retrieved and stored in the 'BaseAddressAuthorizationMessageHandler'. Not a fan of doing this, but it works so my boss is a fan :)

Ahh I see what you mean now! Thanks !!

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

Was this page helpful?
0 / 5 - 0 ratings