1- using IdentityModel . OidcClient ;
21using k8s . Exceptions ;
3- using System . IdentityModel . Tokens . Jwt ;
2+ using System . Net . Http ;
43using System . Net . Http . Headers ;
4+ using System . Text ;
55
66namespace k8s . Authentication
77{
88 public class OidcTokenProvider : ITokenProvider
99 {
10- private readonly OidcClient _oidcClient ;
10+ private readonly string _clientId ;
11+ private readonly string _clientSecret ;
12+ private readonly string _idpIssuerUrl ;
13+
1114 private string _idToken ;
1215 private string _refreshToken ;
1316 private DateTimeOffset _expiry ;
1417
1518 public OidcTokenProvider ( string clientId , string clientSecret , string idpIssuerUrl , string idToken , string refreshToken )
1619 {
20+ _clientId = clientId ;
21+ _clientSecret = clientSecret ;
22+ _idpIssuerUrl = idpIssuerUrl ;
1723 _idToken = idToken ;
1824 _refreshToken = refreshToken ;
19- _oidcClient = getClient ( clientId , clientSecret , idpIssuerUrl ) ;
20- _expiry = getExpiryFromToken ( ) ;
25+
26+ if ( ! string . IsNullOrEmpty ( _idToken ) )
27+ {
28+ _expiry = GetExpiryFromToken ( ) ;
29+ }
2130 }
2231
2332 public async Task < AuthenticationHeaderValue > GetAuthenticationHeaderAsync ( CancellationToken cancellationToken )
@@ -30,49 +39,78 @@ public async Task<AuthenticationHeaderValue> GetAuthenticationHeaderAsync(Cancel
3039 return new AuthenticationHeaderValue ( "Bearer" , _idToken ) ;
3140 }
3241
33- private DateTime getExpiryFromToken ( )
42+ private DateTimeOffset GetExpiryFromToken ( )
3443 {
35- long expiry ;
36- var handler = new JwtSecurityTokenHandler ( ) ;
37- try
44+ var parts = _idToken . Split ( '.' ) ;
45+ if ( parts . Length != 3 )
3846 {
39- var token = handler . ReadJwtToken ( _idToken ) ;
40- expiry = token . Payload . Expiration ?? 0 ;
47+ throw new ArgumentException ( "Invalid JWT token format." ) ;
4148 }
42- catch
49+
50+ var payload = parts [ 1 ] ;
51+ var jsonBytes = Base64UrlDecode ( payload ) ;
52+ var json = Encoding . UTF8 . GetString ( jsonBytes ) ;
53+
54+ using var document = JsonDocument . Parse ( json ) ;
55+ if ( document . RootElement . TryGetProperty ( "exp" , out var expElement ) )
4356 {
44- expiry = 0 ;
57+ var exp = expElement . GetInt64 ( ) ;
58+ var expiryDateTime = DateTimeOffset . FromUnixTimeSeconds ( exp ) ;
59+ return expiryDateTime ;
60+ }
61+ else
62+ {
63+ throw new ArgumentException ( "JWT token does not contain 'exp' claim." ) ;
4564 }
46-
47- return DateTimeOffset . FromUnixTimeSeconds ( expiry ) . UtcDateTime ;
4865 }
4966
50- private OidcClient getClient ( string clientId , string clientSecret , string idpIssuerUrl )
67+ private static byte [ ] Base64UrlDecode ( string input )
5168 {
52- OidcClientOptions options = new OidcClientOptions
69+ var output = input . Replace ( '-' , '+' ) . Replace ( '_' , '/' ) ;
70+ switch ( output . Length % 4 )
5371 {
54- ClientId = clientId ,
55- ClientSecret = clientSecret ?? "" ,
56- Authority = idpIssuerUrl ,
57- } ;
72+ case 2 : output += "==" ; break ;
73+ case 3 : output += "=" ; break ;
74+ }
5875
59- return new OidcClient ( options ) ;
76+ return Convert . FromBase64String ( output ) ;
6077 }
6178
6279 private async Task RefreshToken ( )
6380 {
6481 try
6582 {
66- var result = await _oidcClient . RefreshTokenAsync ( _refreshToken ) . ConfigureAwait ( false ) ;
83+ using var httpClient = new HttpClient ( ) ;
84+ var request = new HttpRequestMessage ( HttpMethod . Post , _idpIssuerUrl ) ;
85+ request . Content = new FormUrlEncodedContent ( new Dictionary < string , string >
86+ {
87+ { "grant_type" , "refresh_token" } ,
88+ { "client_id" , _clientId } ,
89+ { "client_secret" , _clientSecret } ,
90+ { "refresh_token" , _refreshToken } ,
91+ } ) ;
92+
93+ var response = await httpClient . SendAsync ( request ) . ConfigureAwait ( false ) ;
94+ response . EnsureSuccessStatusCode ( ) ;
6795
68- if ( result . IsError )
96+ var responseContent = await response . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ;
97+ var jsonDocument = JsonDocument . Parse ( responseContent ) ;
98+
99+ if ( jsonDocument . RootElement . TryGetProperty ( "id_token" , out var idTokenElement ) )
69100 {
70- throw new Exception ( result . Error ) ;
101+ _idToken = idTokenElement . GetString ( ) ;
71102 }
72103
73- _idToken = result . IdentityToken ;
74- _refreshToken = result . RefreshToken ;
75- _expiry = result . AccessTokenExpiration ;
104+ if ( jsonDocument . RootElement . TryGetProperty ( "refresh_token" , out var refreshTokenElement ) )
105+ {
106+ _refreshToken = refreshTokenElement . GetString ( ) ;
107+ }
108+
109+ if ( jsonDocument . RootElement . TryGetProperty ( "expires_in" , out var expiresInElement ) )
110+ {
111+ var expiresIn = expiresInElement . GetInt32 ( ) ;
112+ _expiry = DateTimeOffset . UtcNow . AddSeconds ( expiresIn ) ;
113+ }
76114 }
77115 catch ( Exception e )
78116 {
0 commit comments