Skip to content

Commit cef7268

Browse files
authored
Token expiry time is read from the token
* Token expiry time is read from the token
1 parent 83e59c7 commit cef7268

File tree

4 files changed

+51
-5
lines changed

4 files changed

+51
-5
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>0.2.2</Version>
3+
<Version>0.2.3</Version>
44
</PropertyGroup>
55
</Project>

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
[![CodeQL](https://github.com/qatoolkit/qatoolkit-auth-net/workflows/CodeQL%20Analyze/badge.svg)](https://github.com/qatoolkit/qatoolkit-auth-net/security/code-scanning)
44
[![Sonarcloud Quality gate](https://github.com/qatoolkit/qatoolkit-auth-net/workflows/Sonarqube%20Analyze/badge.svg)](https://sonarcloud.io/dashboard?id=qatoolkit_qatoolkit-auth-net)
55
[![NuGet package](https://img.shields.io/nuget/v/QAToolKit.Auth?label=QAToolKit.Auth)](https://www.nuget.org/packages/QAToolKit.Auth/)
6+
[![Discord](https://img.shields.io/discord/787220825127780354?color=%23267CB9&label=Discord%20chat)](https://discord.com/invite/tu3WDV5Z?utm_source=Discord%20Widget&utm_medium=Connect)
67

78
## Description
89
`QAToolKit.Auth` is a .NET Standard 2.1 library, that retrieves the JWT access tokens from different identity providers.
@@ -12,7 +13,13 @@ Currently it supports next Identity providers and Oauth2 flows:
1213
- `Azure B2C`: Library supports [AzureB2C](https://azure.microsoft.com/en-us/services/active-directory/external-identities/b2c/) client credentials flow.
1314
- `Identity Server 4`: Library supports [Identity Server 4](https://identityserver.io/) client credentials [flow](https://identityserver4.readthedocs.io/en/latest/quickstarts/1_client_credentials.html)
1415

15-
Supported .NET frameworks and standards: `netstandard2.0`, `netstandard2.1`, `netcoreapp3.1`, `net5.0`
16+
Supported .NET frameworks and standards: `netstandard2.0`, `netstandard2.1`, `netcoreapp3.1`, `net5.0`.
17+
18+
Get in touch with me on:
19+
20+
[![Discord](https://img.shields.io/discord/787220825127780354?color=%23267CB9&label=Discord%20chat)](https://discord.com/invite/tu3WDV5Z?utm_source=Discord%20Widget&utm_medium=Connect)
21+
22+
**Please note**: _The token expiration time is read from the tokens and is used to minimize the hits on the token endpoint. Another benefit is faster tests :)._
1623

1724
## 1. Keycloak support
1825

src/QAToolKit.Auth/DefaultTokenService.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ namespace QAToolKit.Auth
99
{
1010
internal abstract class DefaultTokenService
1111
{
12+
private const int TokenValidityOffsetSeconds = 15;
1213
protected readonly HttpClient _client;
1314
protected readonly Uri _tokenEndpoint;
1415
protected readonly string _clientId;
1516
protected readonly string _secret;
1617
protected readonly string _assemblyName;
1718
protected readonly string _assemblyVersion;
18-
protected string _accessToken = null;
19+
1920
protected string _clientCredentialsToken = null;
21+
private DateTimeOffset? _clientCredentialsTokenValidity = null;
22+
2023
protected string[] _scopes = null;
2124

2225
internal DefaultTokenService(DefaultOptions defaultOptions)
@@ -34,6 +37,11 @@ internal DefaultTokenService(DefaultOptions defaultOptions)
3437

3538
public virtual async Task<string> GetAccessTokenAsync()
3639
{
40+
if (IsAccessTokenValid())
41+
{
42+
return _clientCredentialsToken;
43+
}
44+
3745
await GetClientCredentialsToken();
3846

3947
return _clientCredentialsToken;
@@ -67,13 +75,24 @@ private async Task GetClientCredentialsToken()
6775
dynamic body = JObject.Parse(await response.Content.ReadAsStringAsync());
6876

6977
_clientCredentialsToken = body.access_token;
78+
int expiresIn = body.expires_in;
79+
80+
_clientCredentialsTokenValidity = DateTimeOffset.Now.AddSeconds(expiresIn);
7081

7182
return;
7283
}
7384

7485
throw new UnauthorizedClientException(await response.Content.ReadAsStringAsync());
7586
}
7687

88+
private bool IsAccessTokenValid()
89+
{
90+
if (_clientCredentialsToken == null || !_clientCredentialsTokenValidity.HasValue)
91+
return false;
92+
93+
return _clientCredentialsTokenValidity.Value.AddSeconds(-TokenValidityOffsetSeconds) >= DateTimeOffset.Now;
94+
}
95+
7796
protected HttpRequestMessage CreateBasicTokenEndpointRequest()
7897
{
7998
var request = new HttpRequestMessage(HttpMethod.Post, _tokenEndpoint);

src/QAToolKit.Auth/Keycloak/KeycloakTokenService.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,20 @@ namespace QAToolKit.Auth.Keycloak
99
{
1010
internal class KeycloakTokenService : DefaultTokenService
1111
{
12+
private const int TokenValidityOffsetSeconds = 15;
13+
private readonly string AccessToken = null;
14+
private DateTimeOffset? AccessTokenValidity = null;
15+
1216
public KeycloakTokenService(KeycloakOptions keycloakOptions) : base(keycloakOptions)
1317
{ }
1418

1519
internal async Task<string> ExchangeTokenForUserToken(string userName)
1620
{
21+
if (IsAccessTokenValid())
22+
{
23+
return AccessToken;
24+
}
25+
1726
var impersonatedTokenRequest = CreateBasicTokenEndpointRequest();
1827

1928
if (impersonatedTokenRequest == null)
@@ -36,9 +45,12 @@ internal async Task<string> ExchangeTokenForUserToken(string userName)
3645
{
3746
if (!string.IsNullOrEmpty(contentStr))
3847
{
39-
dynamic content = JObject.Parse(contentStr);
48+
dynamic body = JObject.Parse(contentStr);
49+
int expiresIn = body.expires_in;
50+
51+
AccessTokenValidity = DateTimeOffset.Now.AddSeconds(expiresIn);
4052

41-
return content.access_token;
53+
return body.access_token;
4254
}
4355
else
4456
{
@@ -50,5 +62,13 @@ internal async Task<string> ExchangeTokenForUserToken(string userName)
5062
throw new AccessDeniedException(contentStr);
5163
}
5264
}
65+
66+
private bool IsAccessTokenValid()
67+
{
68+
if (AccessToken == null || !AccessTokenValidity.HasValue)
69+
return false;
70+
71+
return AccessTokenValidity.Value.AddSeconds(-TokenValidityOffsetSeconds) >= DateTimeOffset.Now;
72+
}
5373
}
5474
}

0 commit comments

Comments
 (0)