The token is valid for 1 hour. So you just need to store it for 1 hour before obtaining a new token. Ideally you'd get a token a few minutes before the time limit is up, to decrease the chance that you'll use an invalid token.
So, let's create a class responsible for obtaining and caching a token. This class needs to be registered with your Dependency Injection container as a singleton, so that there's only a single instance. Otherwise you'll needlessly get new tokens all the time. I don't know what Dependency Injection container you're using, so you'll have to research how to register our TokenClient class as a singleton with it.
We'll capture the time we obtained the token in a DateTime field, and the token itself in a field as well.
public class TokenClient
{
readonly IHttpClientFactory _httpClientFactory;
string _cachedToken;
DateTime _tokenRetrievalTime;
public TokenClient(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task<string> GetToken()
{
if (!string.IsNullOrEmpty(_cachedToken) && _tokenRetrievalTime.AddMinutes(55) > DateTime.Now)
{
_cachedToken = await GetTokenFromServer();
_tokenRetrievalTime = DateTime.Now;
return _cachedToken;
}
else
{
return _cachedToken;
}
}
async Task<string> GetTokenFromServer()
{
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("grant_type", "password"));
postData.Add(new KeyValuePair<string, string>("client_id", _clientId));
postData.Add(new KeyValuePair<string, string>("client_secret", _clientSecret));
HttpContent content = new FormUrlEncodedContent(postData);
content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
var client = _httpClientFactory.CreateClient();
var responseResult = await client.PostAsync(_tokenUrl, content);
string token = await responseResult.Content.ReadAsStringAsync();
return token;
}
}
There's a couple of things I'm doing differently here besides just caching the token. I'm using IHttpClientFactory to get an instance of an HttpClient, to avoid the issues detailed in You're Using HttpClient Wrong And It's Destablizing Your Software and You're probably still using HttpClient Wrong And It's Destabilizing Your Software. An even better solution would be to use Flurl, which takes care of those details for you.
The other thing I've changed compared to your code is that I'm properly awaiting the calls that return tasks. That keeps the code from deadlocking and helps keep it running efficiently. For more info on that, see Async Await Best Practices and 8 Await Async Mistakes You Should Avoid.