Looks like you need DelegatingHandler. In two words you can “intercept” your http request and add the Authorization header, then try to execute it and if token was not valid, refresh token and retry one more time. Something like:
public class AuthenticationDelegatingHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var token = await GetTokenAsync();
request.Headers.Authorization = new AuthenticationHeaderValue(token.Scheme, token.AccessToken);
var response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden)
{
token = await RefreshTokenAsync();
request.Headers.Authorization = new AuthenticationHeaderValue(token.Scheme, token.AccessToken);
response = await base.SendAsync(request, cancellationToken);
}
return response;
}
}
You register this delegating handler in Startup.cs like that:
services.AddTransient<AuthenticationDelegatingHandler>();
services.AddHttpClient("MySecuredClient", client =>
{
client.BaseAddress = new Uri("https://baseUrl.com/");
})
.AddHttpMessageHandler<AuthenticationDelegatingHandler>();
And use like that:
var securedClient = _httpClientFactory.CreateClient("MySecuredClient");
securedClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, "v2/relativeUrl"));
Regarding storing refresh token in appsetting.json. I don’t think it’s a good idea as refresh token doesn’t have expiration time. If you can use credentials to obtain new token for the first time, use it, and then store refresh token in-memory for further refreshes.
Here you can see how I manage client credential token refreshes and try to make it work for your scenario.
Update:
Here you can find same idea but implemented by professionals and available in nuget. The usage is very simple:
services.AddAccessTokenManagement(options =>
{
options.Client.Clients.Add("identityserver", new ClientCredentialsTokenRequest
{
Address = "https://demo.identityserver.io/connect/token",
ClientId = "m2m.short",
ClientSecret = "secret",
Scope = "api" // optional
});
});
services.AddHttpClient<MyClient>(client =>
{
client.BaseAddress = new Uri("https://demo.identityserver.io/api/");
})
.AddClientAccessTokenHandler();
Requests sent by MyClient
will always have valid bearer token. The refresh performed automatically.