diff --git a/kubernetes-client.ruleset b/kubernetes-client.ruleset
index 8403c9b..f1221e9 100644
--- a/kubernetes-client.ruleset
+++ b/kubernetes-client.ruleset
@@ -300,6 +300,7 @@
-
+
+
diff --git a/src/KubernetesClient/Authentication/OidcTokenProvider.cs b/src/KubernetesClient/Authentication/OidcTokenProvider.cs
new file mode 100644
index 0000000..4301fd0
--- /dev/null
+++ b/src/KubernetesClient/Authentication/OidcTokenProvider.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Net.Http.Headers;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Rest;
+using IdentityModel.OidcClient;
+using k8s.Exceptions;
+
+namespace k8s.Authentication
+{
+ public class OidcTokenProvider : ITokenProvider
+ {
+ private OidcClient _oidcClient;
+ private string _idToken;
+ private string _refreshToken;
+ private string _accessToken;
+ private DateTime _expiry;
+
+ public OidcTokenProvider(string clientId, string clientSecret, string idpIssuerUrl, string idToken, string refreshToken)
+ {
+ _idToken = idToken;
+ _refreshToken = refreshToken;
+ _oidcClient = getClient(clientId, clientSecret, idpIssuerUrl);
+ }
+
+ public async Task GetAuthenticationHeaderAsync(CancellationToken cancellationToken)
+ {
+ if (_expiry == null || _accessToken == null || DateTime.UtcNow.AddSeconds(30) > _expiry)
+ {
+ await RefreshToken().ConfigureAwait(false);
+ }
+
+ return new AuthenticationHeaderValue("Bearer", _accessToken);
+ }
+
+ private OidcClient getClient(string clientId, string clientSecret, string idpIssuerUrl)
+ {
+ OidcClientOptions options = new OidcClientOptions
+ {
+ ClientId = clientId,
+ ClientSecret = clientSecret ?? "",
+ Authority = idpIssuerUrl,
+ };
+
+ return new OidcClient(options);
+ }
+
+ private async Task RefreshToken()
+ {
+ try
+ {
+ var result =
+ await _oidcClient.RefreshTokenAsync(_refreshToken).ConfigureAwait(false);
+ _accessToken = result.AccessToken;
+ _idToken = result.IdentityToken;
+ _refreshToken = result.RefreshToken;
+ _expiry = result.AccessTokenExpiration;
+ }
+ catch (Exception e)
+ {
+ throw new KubernetesClientException($"Unable to refresh OIDC token. \n {e.Message}", e);
+ }
+ }
+ }
+}
diff --git a/src/KubernetesClient/KubernetesClient.csproj b/src/KubernetesClient/KubernetesClient.csproj
index 9bae5ce..3712b47 100644
--- a/src/KubernetesClient/KubernetesClient.csproj
+++ b/src/KubernetesClient/KubernetesClient.csproj
@@ -31,5 +31,6 @@
+
diff --git a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs
index 0322989..06b983a 100644
--- a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs
+++ b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs
@@ -40,7 +40,7 @@ namespace k8s
///
///
/// If multiple kubeconfig files are specified in the KUBECONFIG environment variable,
- /// merges the files, where first occurence wins. See https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#merging-kubeconfig-files.
+ /// merges the files, where first occurrence wins. See https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#merging-kubeconfig-files.
///
/// Instance of the class
public static KubernetesClientConfiguration BuildDefaultConfig()
@@ -214,7 +214,7 @@ namespace k8s
}
///
- /// Validates and Intializes Client Configuration
+ /// Validates and Initializes Client Configuration
///
/// Kubernetes Configuration
/// Current Context
@@ -346,7 +346,8 @@ namespace k8s
if (userDetails.UserCredentials.AuthProvider != null)
{
if (userDetails.UserCredentials.AuthProvider.Config != null
- && userDetails.UserCredentials.AuthProvider.Config.ContainsKey("access-token"))
+ && (userDetails.UserCredentials.AuthProvider.Config.ContainsKey("access-token")
+ || userDetails.UserCredentials.AuthProvider.Config.ContainsKey("id-token")))
{
switch (userDetails.UserCredentials.AuthProvider.Name)
{
@@ -390,6 +391,29 @@ namespace k8s
userCredentialsFound = true;
break;
}
+
+ case "oidc":
+ {
+ var config = userDetails.UserCredentials.AuthProvider.Config;
+ AccessToken = config["id-token"];
+ if (config.ContainsKey("client-id")
+ && config.ContainsKey("idp-issuer-url")
+ && config.ContainsKey("id-token")
+ && config.ContainsKey("refresh-token"))
+ {
+ string clientId = config["client-id"];
+ string clientSecret = config.ContainsKey("client-secret") ? config["client-secret"] : null;
+ string idpIssuerUrl = config["idp-issuer-url"];
+ string idToken = config["id-token"];
+ string refreshToken = config["refresh-token"];
+
+ TokenProvider = new OidcTokenProvider(clientId, clientSecret, idpIssuerUrl, idToken, refreshToken);
+
+ userCredentialsFound = true;
+ }
+
+ break;
+ }
}
}
}
@@ -656,7 +680,7 @@ namespace k8s
/// file is located. When , the paths will be considered to be relative to the current working directory.
/// Instance of the class
///
- /// The kube config files will be merges into a single , where first occurence wins.
+ /// The kube config files will be merges into a single , where first occurrence wins.
/// See https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#merging-kubeconfig-files.
///
internal static K8SConfiguration LoadKubeConfig(FileInfo[] kubeConfigs, bool useRelativePaths = true)
@@ -672,7 +696,7 @@ namespace k8s
/// file is located. When , the paths will be considered to be relative to the current working directory.
/// Instance of the class
///
- /// The kube config files will be merges into a single , where first occurence wins.
+ /// The kube config files will be merges into a single , where first occurrence wins.
/// See https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#merging-kubeconfig-files.
///
internal static async Task LoadKubeConfigAsync(