I am using Auth0 for user login in my Blazor project, and additionally authenticate the user in a WebAPI endpoint that supplies a jwt for subsequent calls. This all works fine.
If a user's Auth0 login expires, the user gets correctly redirected to a login page.
The problem is when the jwt expires. The user is still authenticated in the web app, but when they hit the WebAPI they get an Unauthorized (401) response as expected.
I'd like to eventually implement code to refresh the token, but for now I would settle for a redirect to a Logout controller to force them to re-authenticate.
I have tried to redirect from a custom handler that inherits from HttpClientHandler:
var unauthorizedHandler = new UnauthorizedHandler();
var httpClient = new HttpClient(unauthorizedHandler);
public class UnauthorizedHandler : HttpClientHandler
{
    private IHttpContextAccessor _httpContextAccessor;
    public void Add(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);
        
        if (response.StatusCode == HttpStatusCode.Unauthorized)
        {
            _httpContextAccessor.HttpContext.Response.Redirect("/Identity/Logout", true);
        }
        return response;
    }
}
The redirect results in: System.InvalidOperationException: StatusCode cannot be set because the response has already started.
I am also using NSwag's generated C# client, and tried to similarly redirect from the ProcessResponse partial method, but got the same/similar error message.
If I catch the exception and redirect via NavigationManager in the actual Blazor page, it works fine, but I'd like to handle the problem in a cross-cutting way.
How can I intercept an Unauthorized error in the HttpClient and redirect automatically?
I have dealed with similar issues in the past. This is one possible approach I suggest you. First, the errors is indicating that once the http response starts, you can't modify it to add a redirect status code, so based on this try this:
So in summary my idea is to try something like this:
public class UnauthorizedHandler : HttpClientHandler
{
    public event Action UnauthorizedStatusReceived;
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);
        if (response.StatusCode == HttpStatusCode.Unauthorized)
        {
            // Notice this line
            UnauthorizedStatusReceived?.Invoke();
        }
        return response;
    }
}
Then register the handler and the IHttpContextAncessor:
services.AddSingleton<UnauthorizedHandler>();
services.AddHttpContextAccessor();
And finally subscribe to the UnauthorizedStatusReceived event in your Blazor component and use NavigationManager to do the redirect:
@inject UnauthorizedHandler UnauthorizedHandler
@inject NavigationManager NavigationManager
protected override void OnInitialized()
{
    UnauthorizedHandler.UnauthorizedStatusReceived += HandleUnauthorized;
}
private void HandleUnauthorized()
{
    NavigationManager.NavigateTo("/Identity/Logout");
}
I hope this helps you to solve this or get closer to it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With