For each API call in my App, I want to check whether the user has an expired JWT, and if so, I want to get a new one using a refresh token, and then proceed with the original request to API. This is supposed to all work in the background without the APP user experiencing any interruptions or need to login again.
I create my HttpClient like this:
static DelegatingHandler handler = new AuthenticationHandler();
static HttpClient httpClient = new HttpClient(handler)
{
BaseAddress = new Uri("https://10.0.2.2:5001/api/v1")
};
AuthenticationHandler is a custom DelegatingHandler which has an override SendAsync
method. Inside that method I check if request has status Unauthorised
:
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
And if it does, I need to send another request to my API with the currently owned JWT and Refresh tokens to generate new pair of tokens... Since this is an API call in the middle of another API call (as it all happens inside the custom DelegatingHandler which is a parameter for constructing my main HttpClient) - does refreshing the token needs to happen using a second HttpClient that I need to create literally to make the refresh token call?
I can't see how can I use the same HttpClient for this, how is this usually being done?
EDIT:
I can't see how I could use the same HttpClient for refreshToken call from inside AuthenticationHandler, as the handler is used to construct the HttpClient. Feels like a circular reference. I just have no idea how others do it in their code... I currently implemented it by using that second HttpClient which I only use for that one refreshToken
call, and it works, but I have a feeling that there is a cleaner way to achieve this?
Btw, my (not refactored yet) SendAsync method inside AuthenticationHandler looks like this currently:
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
try
{
HttpResponseMessage response = new HttpResponseMessage();
request = CheckForAuthToken(request);
response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
for (int i = 1; i == _maxRefreshAttempts; i++)
{
// Here I make a call to the API to refresh and return a new JWT, The authApiService uses a different HttpClient
RefreshTokenRequestModel refreshTokenRequestModel = new RefreshTokenRequestModel
{
Token = await SecureStorage.GetAsync("jwtToken"),
RefreshToken = await SecureStorage.GetAsync("refreshToken")
};
var apiResponse = await authApiService.RefreshToken(refreshTokenRequestModel);
if (apiResponse.IsSuccessStatusCode)
{
await SecureStorage.SetAsync("jwtToken", apiResponse.Content.Token);
await SecureStorage.SetAsync("refreshToken", apiResponse.Content.RefreshToken);
request = CheckForAuthToken(request);
response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
}
}
return response;
}
catch (Exception e)
{
throw e;
}
}