Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save andriihomiak/87f5c3a1215d09f567bd4ea851e54da4 to your computer and use it in GitHub Desktop.
Save andriihomiak/87f5c3a1215d09f567bd4ea851e54da4 to your computer and use it in GitHub Desktop.
Retry on Unauthorized issue
httpClient = new HttpClient(new RetryOnUnauthorizedMessageHandler(new HttpClientHandler()));
/// <summary>
/// See https://stackoverflow.com/a/49304655
/// </summary>
public class RetryOnUnauthorizedMessageHandler : DelegatingHandler
{
public RetryOnUnauthorizedMessageHandler(HttpMessageHandler innerHandler) : base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
//test for 401 and actual bearer token in initial request
var wasAuthorized = !string.IsNullOrWhiteSpace(request.Headers.Authorization?.Parameter);
if (response.StatusCode != HttpStatusCode.Unauthorized || !wasAuthorized) return response; // authorized or no token is needed
//if 401
try
{
var log = Mvx.Resolve<IMvxLog>();
log.Info("Got Unauthorized, trying to refresh token");
var uow = Mvx.Resolve<IUnitOfWork>();
var model = uow.Token.Get();
var data = new Dictionary<string, string>
{
{"grant_type", "refresh_token"},
{"refresh_token", model.RefreshToken}
};
var requestUri = new Uri($"{Constants.UriAuthApi}api/token");
var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri)
{
Content = new FormUrlEncodedContent(data)
};
using (var refreshResponse = await base.SendAsync(requestMessage, cancellationToken).ConfigureAwait(false))
{
if (refreshResponse.StatusCode == HttpStatusCode.Unauthorized)
{
log.Error("Refresh token is not valid. Signing out");
await Mvx.Resolve<IMvxNavigationService>()
.CustomNavigate<LoginContainerViewModel>(NavigationType.ClearBackstack);
}
else if(refreshResponse.IsSuccessStatusCode)
{
var rawResponse = await refreshResponse.Content.ReadAsStringAsync();
var authModel = JsonConvert.DeserializeObject<AuthModel>(rawResponse);
log.Info($"Successfully refreshed token: {authModel.AccessToken.Substring(0, 7)}...");
request.Headers.Remove("Authorization");
request.Headers.Add("Authorization", "bearer " + authModel.AccessToken);
if (uow.Token.Update(authModel))
{
log.Info("Token saved, retying initial request...");
response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
}
else
{
//TODO
}
}
return response;
}
catch (Exception e)
{
Analytics.TrackEvent("Token refresh failed");
throw e;
}
}
}
//when creating httpClient like this - requests are very slow
httpClient = new HttpClient(new RetryOnUnauthorizedMessageHandler(new HttpClientHandler()));
//but when doing like this - everything works fast (but no desired behaviour)
httpClient = new HttpClient(new HttpClientHandler());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment