Created
July 19, 2017 15:31
-
-
Save anderbakk/03b02bb764cdd94908d93424de16124b to your computer and use it in GitHub Desktop.
Caching TokenResponse from IdentityModel.Client.TokenClient
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Diagnostics; | |
| using IdentityModel.Client; | |
| namespace IfInsurance.Waypoint.Cached.Identity.TokenClient | |
| { | |
| public interface ICachedTokenClient | |
| { | |
| string GetToken(bool forceFreshToken = false); | |
| } | |
| public class CachedTokenClient : IClient | |
| { | |
| private readonly object _lockObject = new object(); | |
| private TokenResponse _cachedTokenResponse; | |
| private DateTime _timeToRefreshToken; | |
| private readonly string _authority; | |
| private readonly string _clientId; | |
| private readonly string _clientSecret; | |
| private readonly string _api; | |
| public CachedTokenClient(string authority, string clientId, string clientSecret, string api) | |
| { | |
| _authority = string.IsNullOrEmpty(authority) ? throw new ArgumentNullException(nameof(authority)) : authority; | |
| _clientId = string.IsNullOrEmpty(clientId) ? throw new ArgumentNullException(nameof(clientId)) : clientId; | |
| _clientSecret = string.IsNullOrEmpty(clientSecret) ? throw new ArgumentNullException(nameof(clientSecret)) : clientSecret; | |
| _api = string.IsNullOrEmpty(api) ? throw new ArgumentNullException(nameof(api)) : api; | |
| } | |
| public string GetToken(bool forceFreshToken = false) | |
| { | |
| lock(_lockObject) | |
| { | |
| if (forceFreshToken || HasValidToken() == false) | |
| { | |
| RefreshToken(); | |
| } | |
| return _cachedTokenResponse.AccessToken; | |
| } | |
| } | |
| private void RefreshToken() | |
| { | |
| var disco = GetDiscoveryResponse(); | |
| var tokenClient = new IdentityModel.Client.TokenClient(disco.TokenEndpoint, _clientId, | |
| _clientSecret); | |
| var tokenResponse = tokenClient.RequestClientCredentialsAsync(_api) | |
| .ConfigureAwait(false).GetAwaiter().GetResult(); | |
| if (tokenResponse == null || tokenResponse.IsError) | |
| throw new ArgumentException(tokenResponse?.ErrorDescription ?? "Error requesting api access"); | |
| _timeToRefreshToken = DateTime.Now.AddSeconds(tokenResponse.ExpiresIn); | |
| _cachedTokenResponse = tokenResponse; | |
| Trace.TraceInformation($"Token retrieved, expires in {tokenResponse.ExpiresIn} seconds"); | |
| } | |
| private bool HasValidToken() | |
| { | |
| return _cachedTokenResponse != null && DateTime.Now.AddMinutes(-10) < _timeToRefreshToken; | |
| } | |
| private DiscoveryResponse GetDiscoveryResponse() | |
| { | |
| var disco = DiscoveryClient.GetAsync(_authority).GetAwaiter().GetResult(); | |
| if (disco == null || disco.IsError || string.IsNullOrEmpty(disco.TokenEndpoint)) | |
| throw new Exception($"Could not get TokenEndpoint from DiscoveryClient"); | |
| return disco; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I think there's an error in your
HasValidToken()logic.It looks as though you want to refresh the token 10 minutes before it expires. In that case,
DateTime.UtcNow.AddMinutes(-10)should beDateTime.UtcNow.AddMinutes(10).If
_timeToRefreshTokenwas say, set to 11am andHasValidToken()ran at 11.06 am. 11.06am - 10 minutes is 10.56am, which means your logic says the token is still valid, even though it expired at 11am. So what you're after is: