AuthenticationApiClient caches JsonWebKeySet only for the first 10 minutes for GetTokenAsync(RefreshTokenRequest request)
nmuhundanwow opened this issue · 2 comments
Checklist
- I have looked into the Readme and have not found a suitable solution or answer.
- I have looked into the API documentation and have not found a suitable solution or answer.
- I have searched the issues and have not found a suitable solution or answer.
- I have searched the Auth0 Community forums and have not found a suitable solution or answer.
- I agree to the terms within the Auth0 Code of Conduct.
Description
Expection
When a single instance of AuthenticationApiClient
is created and GetTokenAsync(RefreshTokenRequest request, ....)
is called multiple times, the expectation is https://metro60-uat.woolworths-dev.auth0app.com/.well-known/jwks.json
is only called every 10 minutes as per the library and cached JsonWebKeySet
is used other times.
Actual
The caching of JsonWebKeySet
in AuthenticationApiClient
works as expected for the first 10 minutes when GetTokenAsync(RefreshTokenRequest request, ....)
is called multiple times. However after 10 minutes are elapsed, any number of subsequent calls to GetTokenAsync(RefreshTokenRequest request, ....)
will always lead AuthenticationApiClient
calling https://metro60-uat.woolworths-dev.auth0app.com/.well-known/openid-configuration
and https://metro60-uat.woolworths-dev.auth0app.com/.well-known/jwks.json
to retrieve JsonWebKeySet
but never caches it
Solution
The problem is in this line of code
cache.TryAdd(key, new Entry { Task = task, CachedAt = now });
will not replace the old cache entry and this check will always return false after first 10 minutes.
One such solution is to replace that line to
cache[key] = new Entry { Task = task, CachedAt = now };
Reproduction
This is the code to demonstrate the behavior
public class Auth0AuthenticationApiClientHandler: HttpClientHandler
{
private readonly ILogger<Auth0AuthenticationApiClientHandler> _logger;
public Auth0AuthenticationApiClientHandler(ILogger<Auth0AuthenticationApiClientHandler> logger)
{
_logger = logger;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
_logger.LogInformation("{Time}: Calling {Method} {Url}", DateTimeOffset.UtcNow.ToString("s", System.Globalization.CultureInfo.InvariantCulture), request.Method, request.RequestUri);
return base.SendAsync(request, cancellationToken);
}
}
...
...
...
_auth0OtpClient= AuthenticationApiClient("Auth0 Host URL",
new HttpClientAuthenticationConnection(auth0AuthenticationApiClientHandler));
...
...
...
_logger.LogInformation("{Time}: Start of getting new refresh token", DateTimeOffset.UtcNow.ToString("s", System.Globalization.CultureInfo.InvariantCulture));
var refreshTokenResponse = await _auth0OtpClient.GetTokenAsync(refreshOtpTokenRequest, cancellationToken);
_logger.LogInformation("{Time}: End of getting new refresh token", DateTimeOffset.UtcNow.ToString("s", System.Globalization.CultureInfo.InvariantCulture));
And logs were
2023-12-21T07:17:20: Start of getting new refresh token
2023-12-21T07:17:20: Calling POST https://{{DOMAIN}}/oauth/token
2023-12-21T07:17:21: Calling GET https://{{DOMAIN}}/.well-known/openid-configuration
2023-12-21T07:17:21: Calling GET https://{{DOMAIN}}/.well-known/jwks.json
2023-12-21T07:17:21: End of getting new refresh token
2023-12-21T07:17:59: Start of getting new refresh token
2023-12-21T07:17:59: Calling POST https://{{DOMAIN}}/oauth/token
2023-12-21T07:17:59: End of getting new refresh token
2023-12-21T07:18:21: Start of getting new refresh token
2023-12-21T07:18:21: Calling POST https://{{DOMAIN}}/oauth/token
2023-12-21T07:18:22: End of getting new refresh token
2023-12-21T07:26:22: Start of getting new refresh token
2023-12-21T07:26:22: Calling POST https://{{DOMAIN}}/oauth/token
2023-12-21T07:26:22: End of getting new refresh token
2023-12-21T07:27:59: Start of getting new refresh token
2023-12-21T07:27:59: Calling POST https://{{DOMAIN}}/oauth/token
2023-12-21T07:28:00: Calling GET https://{{DOMAIN}}/.well-known/openid-configuration
2023-12-21T07:28:00: Calling GET https://{{DOMAIN}}/.well-known/jwks.json
2023-12-21T07:28:00: End of getting new refresh token
2023-12-21T07:28:14: Start of getting new refresh token
2023-12-21T07:28:14: Calling POST https://{{DOMAIN}}/oauth/token
2023-12-21T07:28:14: Calling GET https://{{DOMAIN}}/.well-known/openid-configuration
2023-12-21T07:28:14: Calling GET https://{{DOMAIN}}/.well-known/jwks.json
2023-12-21T07:28:14: End of getting new refresh token
2023-12-21T07:28:21: Start of getting new refresh token
2023-12-21T07:28:21: Calling POST https://{{DOMAIN}}/oauth/token
2023-12-21T07:28:22: Calling GET https://{{DOMAIN}}/.well-known/openid-configuration
2023-12-21T07:28:22: Calling GET https://{{DOMAIN}}/.well-known/jwks.json
2023-12-21T07:28:22: End of getting new refresh token
As it can be observed, the first call to GetTokenAsync
was made on 2023-12-21T07:17:20 and OIDC endpoints called for the first time and they were never called in the next 10 minutes for subsequent calls of GetTokenAsync
, until 2023-12-21T07:26:22. However after 2023-12-21T07:27:59, every calls to GetTokenAsync
lead AuthenticationApiClient
to call OIDC endpoints every time.
Additional context
No response
auth0.net version
7.25.1
.NET version
8.0
Thanks!
I opened a PR to fix this, can you take a look and see if this would solve your use-case as well?
Thanks!
I opened a PR to fix this, can you take a look and see if this would solve your use-case as well?
Yes, the PR will fix it. Thanks for the quick PR.