From 2032280cc8a5a1d4f6617561ca7c77a598d9f5bd Mon Sep 17 00:00:00 2001 From: dervoeti Date: Wed, 25 Feb 2026 21:18:42 +0100 Subject: [PATCH 1/4] feat: add support for specifying a clientAuthenticationMethod for OIDC --- .../stackable-operator/crds/DummyCluster.yaml | 10 +++ .../src/crd/authentication/oidc/mod.rs | 63 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/crates/stackable-operator/crds/DummyCluster.yaml b/crates/stackable-operator/crds/DummyCluster.yaml index e630b8b0e..7f2e06039 100644 --- a/crates/stackable-operator/crds/DummyCluster.yaml +++ b/crates/stackable-operator/crds/DummyCluster.yaml @@ -30,6 +30,16 @@ spec: description: This field contains OIDC-specific configuration. It is only required in case OIDC is used. nullable: true properties: + clientAuthenticationMethod: + default: client_secret_basic + description: 'The client authentication method used when communicating with the token endpoint. Defaults to `client_secret_basic`. The required contents of `clientCredentialsSecret` depend on the chosen method: secret-based methods (`client_secret_basic`, `client_secret_post`, `client_secret_jwt`) expect a client secret, while `private_key_jwt` expects a private key.' + enum: + - client_secret_basic + - client_secret_post + - client_secret_jwt + - private_key_jwt + - none + type: string clientCredentialsSecret: description: |- A reference to the OIDC client credentials secret. The secret contains diff --git a/crates/stackable-operator/src/crd/authentication/oidc/mod.rs b/crates/stackable-operator/src/crd/authentication/oidc/mod.rs index dd7aa35aa..10c7b436c 100644 --- a/crates/stackable-operator/src/crd/authentication/oidc/mod.rs +++ b/crates/stackable-operator/src/crd/authentication/oidc/mod.rs @@ -90,6 +90,50 @@ pub mod versioned { Keycloak, } + /// OAuth2 client authentication methods as defined in the OpenID Connect Core spec. + /// These methods are used by clients to authenticate to the authorization server + /// when using the token endpoint. + /// + /// See for details. + #[derive( + Clone, + Copy, + Debug, + Default, + Deserialize, + Eq, + Hash, + JsonSchema, + Ord, + PartialEq, + PartialOrd, + Serialize, + )] + #[serde(rename_all = "snake_case")] + pub enum ClientAuthenticationMethod { + /// Authenticate using HTTP Basic authentication with client_id and client_secret. + /// This is the default method according to the OIDC spec. + #[default] + #[serde(rename = "client_secret_basic")] + ClientSecretBasic, + + /// Send client_id and client_secret in the request body. + #[serde(rename = "client_secret_post")] + ClientSecretPost, + + /// Authenticate using a JWT signed with an HMAC SHA algorithm using the client_secret. + #[serde(rename = "client_secret_jwt")] + ClientSecretJwt, + + /// Authenticate using a JWT signed with the client's private key. + #[serde(rename = "private_key_jwt")] + PrivateKeyJwt, + + /// No client authentication (for public clients or implicit flow). + #[serde(rename = "none")] + None, + } + /// OIDC specific config options. These are set on the product config level. #[derive( Clone, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize, @@ -111,6 +155,25 @@ pub mod versioned { #[serde(default)] pub extra_scopes: Vec, + /// The OAuth2 client authentication method to use for token endpoint requests. + /// Defaults to [`ClientAuthenticationMethod::ClientSecretBasic`]. + /// + /// The contents and format of the `clientCredentialsSecret` are dependent on the selected + /// method. For example, [`ClientAuthenticationMethod::ClientSecretBasic`] and + /// [`ClientAuthenticationMethod::ClientSecretPost`] require a client secret string, whereas + /// [`ClientAuthenticationMethod::PrivateKeyJwt`] requires a private key. + /// + /// See [`ClientAuthenticationMethod`] for available options. + #[schemars( + description = "The client authentication method used when communicating with the token \ + endpoint. Defaults to `client_secret_basic`. The required contents of \ + `clientCredentialsSecret` depend on the chosen method: secret-based methods \ + (`client_secret_basic`, `client_secret_post`, `client_secret_jwt`) expect a client \ + secret, while `private_key_jwt` expects a private key." + )] + #[serde(default)] + pub client_authentication_method: ClientAuthenticationMethod, + // If desired, operators can add custom fields that are only needed for this specific product. // They need to create a struct holding them and pass that as `T`. #[serde(flatten)] From 2b4b601811442f3b78a04c0ee4c3e0ca64bf2286 Mon Sep 17 00:00:00 2001 From: Lukas Krug Date: Thu, 5 Mar 2026 16:31:40 +0100 Subject: [PATCH 2/4] Update crates/stackable-operator/src/crd/authentication/oidc/mod.rs Co-authored-by: Techassi --- crates/stackable-operator/src/crd/authentication/oidc/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/stackable-operator/src/crd/authentication/oidc/mod.rs b/crates/stackable-operator/src/crd/authentication/oidc/mod.rs index 10c7b436c..8f8afb5fa 100644 --- a/crates/stackable-operator/src/crd/authentication/oidc/mod.rs +++ b/crates/stackable-operator/src/crd/authentication/oidc/mod.rs @@ -91,6 +91,7 @@ pub mod versioned { } /// OAuth2 client authentication methods as defined in the OpenID Connect Core spec. + /// /// These methods are used by clients to authenticate to the authorization server /// when using the token endpoint. /// From bf01da41c6f04fe5dc5fc13c376e9526d70e4380 Mon Sep 17 00:00:00 2001 From: Lukas Krug Date: Thu, 5 Mar 2026 16:31:47 +0100 Subject: [PATCH 3/4] Update crates/stackable-operator/src/crd/authentication/oidc/mod.rs Co-authored-by: Techassi --- crates/stackable-operator/src/crd/authentication/oidc/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stackable-operator/src/crd/authentication/oidc/mod.rs b/crates/stackable-operator/src/crd/authentication/oidc/mod.rs index 8f8afb5fa..d1a93c971 100644 --- a/crates/stackable-operator/src/crd/authentication/oidc/mod.rs +++ b/crates/stackable-operator/src/crd/authentication/oidc/mod.rs @@ -159,7 +159,7 @@ pub mod versioned { /// The OAuth2 client authentication method to use for token endpoint requests. /// Defaults to [`ClientAuthenticationMethod::ClientSecretBasic`]. /// - /// The contents and format of the `clientCredentialsSecret` are dependent on the selected + /// The contents and format of the `clientCredentialsSecret` depend on the selected /// method. For example, [`ClientAuthenticationMethod::ClientSecretBasic`] and /// [`ClientAuthenticationMethod::ClientSecretPost`] require a client secret string, whereas /// [`ClientAuthenticationMethod::PrivateKeyJwt`] requires a private key. From c2b4d6579087565bc54df8d19764218563073bd4 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Thu, 5 Mar 2026 16:32:31 +0100 Subject: [PATCH 4/4] chore: remove unnecessary serde attributes --- crates/stackable-operator/src/crd/authentication/oidc/mod.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/crates/stackable-operator/src/crd/authentication/oidc/mod.rs b/crates/stackable-operator/src/crd/authentication/oidc/mod.rs index d1a93c971..c818d77b4 100644 --- a/crates/stackable-operator/src/crd/authentication/oidc/mod.rs +++ b/crates/stackable-operator/src/crd/authentication/oidc/mod.rs @@ -115,23 +115,18 @@ pub mod versioned { /// Authenticate using HTTP Basic authentication with client_id and client_secret. /// This is the default method according to the OIDC spec. #[default] - #[serde(rename = "client_secret_basic")] ClientSecretBasic, /// Send client_id and client_secret in the request body. - #[serde(rename = "client_secret_post")] ClientSecretPost, /// Authenticate using a JWT signed with an HMAC SHA algorithm using the client_secret. - #[serde(rename = "client_secret_jwt")] ClientSecretJwt, /// Authenticate using a JWT signed with the client's private key. - #[serde(rename = "private_key_jwt")] PrivateKeyJwt, /// No client authentication (for public clients or implicit flow). - #[serde(rename = "none")] None, }