Repository: openshift-kni/oran-o2ims
Pull request #703: Add shared common authentication data types
Author: login: sakhoury
Labels: name: approved
description: Indicates a PR has been approved by an approver from all required OWNERS files.
name: lgtm
description: Indicates that a PR is ready to be merged.
Created: 2025-05-30T14:55:04Z | Merged: 2025-05-30T17:48:51Z

# Summary

This PR refactors the CRDs to use shared common authentication types. The `HardwarePlugin` CRD is also updated to incorporate the following fields:
- `CaBundleName`
- `AuthConfig`

/cc @alegacy @browsell 


Diff:
diff --git a/api/common/common_types.go b/api/common/common_types.go
new file mode 100644
index 000000000..2168e5efb
--- /dev/null
+++ b/api/common/common_types.go
@@ -0,0 +1,100 @@
+/*
+SPDX-FileCopyrightText: Red Hat
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package common
+
+// +genclient
+
+// +kubebuilder:object:generate=true
+// TLSConfig defines the configuration for TLS-specific attributes.
+type TLSConfig struct {
+	// SecretName specifies the name of a secret (in the current namespace) containing an X.509 certificate and
+	// private key. The secret must include 'tls.key' and 'tls.crt' keys. If the certificate is signed by
+	// intermediate CA(s), the full certificate chain should be included in the certificate file, with the
+	// leaf certificate first and the root CA last. The certificate's Common Name (CN) or Subject Alternative
+	// Name (SAN) should align with the service's fully qualified domain name to support both ingress and
+	// outgoing client certificate use cases.
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="TLS Certificate"
+	SecretName *string `json:"secretName"`
+}
+
+// +kubebuilder:object:generate=true
+// OAuthClientConfig defines the configurable client attributes that represent the authentication mechanism.  This is currently
+// expected to be a way to acquire a token from an OAuth2 server.
+type OAuthClientConfig struct {
+	// URL represents the base URL of the authorization server. (e.g., https://keycloak.example.com/realms/oran)
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth URL",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	URL string `json:"url"`
+	// TokenEndpoint represents the API endpoint used to acquire a token (e.g., /protocol/openid-connect/token) which
+	// will be appended to the base URL to form the full URL
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Token Endpoint",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	TokenEndpoint string `json:"tokenEndpoint"`
+	// ClientSecretName represents the name of a secret (in the current namespace) which contains the client-id and
+	// client-secret values used by the OAuth client.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Client Secret",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	ClientSecretName string `json:"clientSecretName"`
+	// Scopes represents the OAuth scope values to request when acquiring a token.  Typically, this should be set to
+	// "openid" in addition to any other scopes that the SMO specifically requires (e.g., "roles", "groups", etc...) to
+	// authorize our requests
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Scopes",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	Scopes []string `json:"scopes"`
+}
+
+// +kubebuilder:object:generate=true
+// AuthType defines the authorization type used for authentication.
+type AuthType string
+
+const (
+	// ServiceAccount represents authentication using a Kubernetes ServiceAccount token. This method assumes
+	// the server provides a service running within the same Kubernetes cluster and leverages a ServiceAccount
+	// to authenticate requests. It is used for internal cluster communication, where the client presents a
+	// JWT token issued by the cluster's Kubernetes API server.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="ServiceAccount Authentication"
+	ServiceAccount AuthType = "ServiceAccount"
+
+	// Basic represents authentication using HTTP Basic Authentication. This method uses a username and password
+	// combination to authenticate requests, typically encoded in the Authorization header of HTTP requests.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Basic Authentication"
+	Basic AuthType = "Basic"
+
+	// OAuth represents authentication using an OAuth2-based mechanism. This method involves acquiring a token
+	// from an OAuth2 server using the client_credentials grant type, which is then used to authenticate
+	// requests, typically via a Bearer token in the Authorization header. Only the client_credentials grant
+	// type is supported. Configuration details for OAuth, including the authorization server URL and client
+	// credentials, are specified in the OAuthConfig struct.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Authentication"
+	OAuth AuthType = "OAuth"
+)
+
+// +kubebuilder:object:generate=true
+// AuthConfig defines the configuration for different authentication types.
+// This struct encapsulates the settings required for ServiceAccount, Basic, and OAuth authentication mechanisms.
+type AuthClientConfig struct {
+	// Type specifies the authentication type to be used (e.g., ServiceAccount, Basic, or OAuth).
+	//+kubebuilder:validation:Enum=ServiceAccount;Basic;OAuth
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Authentication Type",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:select:ServiceAccount","urn:alm:descriptor:com.tectonic.ui:select:Basic","urn:alm:descriptor:com.tectonic.ui:select:OAuth"}
+	Type AuthType `json:"type"`
+
+	// BasicAuthSecret represents the name of a secret (in the current namespace) containing the username
+	// and password for Basic authentication. The secret is expected to contain 'username' and 'password' keys.
+	// This field is required when Type is set to "Basic".
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Basic Auth Secret",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	BasicAuthSecret *string `json:"basicAuthSecret,omitempty"`
+
+	// OAuthConfig holds the configuration for OAuth2-based authentication, including the authorization server
+	// URL, token endpoint, and client credentials. This field is required when Type is set to "OAuth".
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Configuration"
+	OAuthClientConfig *OAuthClientConfig `json:"oauthConfig,omitempty"`
+
+	// TLSConfig specifies the TLS configuration for secure communication, including the certificate and private
+	// key. This field is optional and can be used with any authentication type to enable TLS for the connection.
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="TLS Configuration"
+	TLSConfig *TLSConfig `json:"tlsConfig,omitempty"`
+}
diff --git a/api/common/go.mod b/api/common/go.mod
new file mode 100644
index 000000000..383f9062d
--- /dev/null
+++ b/api/common/go.mod
@@ -0,0 +1,4 @@
+module github.com/openshift-kni/oran-o2ims/api/common
+
+go 1.22.0
+
diff --git a/api/common/zz_generated.deepcopy.go b/api/common/zz_generated.deepcopy.go
new file mode 100644
index 000000000..5d5076870
--- /dev/null
+++ b/api/common/zz_generated.deepcopy.go
@@ -0,0 +1,81 @@
+//go:build !ignore_autogenerated
+
+/*
+SPDX-FileCopyrightText: Red Hat
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package common
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AuthClientConfig) DeepCopyInto(out *AuthClientConfig) {
+	*out = *in
+	if in.BasicAuthSecret != nil {
+		in, out := &in.BasicAuthSecret, &out.BasicAuthSecret
+		*out = new(string)
+		**out = **in
+	}
+	if in.OAuthClientConfig != nil {
+		in, out := &in.OAuthClientConfig, &out.OAuthClientConfig
+		*out = new(OAuthClientConfig)
+		(*in).DeepCopyInto(*out)
+	}
+	if in.TLSConfig != nil {
+		in, out := &in.TLSConfig, &out.TLSConfig
+		*out = new(TLSConfig)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthClientConfig.
+func (in *AuthClientConfig) DeepCopy() *AuthClientConfig {
+	if in == nil {
+		return nil
+	}
+	out := new(AuthClientConfig)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *OAuthClientConfig) DeepCopyInto(out *OAuthClientConfig) {
+	*out = *in
+	if in.Scopes != nil {
+		in, out := &in.Scopes, &out.Scopes
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OAuthClientConfig.
+func (in *OAuthClientConfig) DeepCopy() *OAuthClientConfig {
+	if in == nil {
+		return nil
+	}
+	out := new(OAuthClientConfig)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TLSConfig) DeepCopyInto(out *TLSConfig) {
+	*out = *in
+	if in.SecretName != nil {
+		in, out := &in.SecretName, &out.SecretName
+		*out = new(string)
+		**out = **in
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig.
+func (in *TLSConfig) DeepCopy() *TLSConfig {
+	if in == nil {
+		return nil
+	}
+	out := new(TLSConfig)
+	in.DeepCopyInto(out)
+	return out
+}
diff --git a/api/hardwaremanagement/go.mod b/api/hardwaremanagement/go.mod
index 95dfb26c2..90b5e334c 100644
--- a/api/hardwaremanagement/go.mod
+++ b/api/hardwaremanagement/go.mod
@@ -3,6 +3,7 @@ module github.com/openshift-kni/oran-o2ims/api/hardwaremanagement
 go 1.22.0
 
 require (
+	github.com/openshift-kni/oran-o2ims/api/common v0.0.0-00010101000000-000000000000
 	k8s.io/apimachinery v0.31.8
 	sigs.k8s.io/controller-runtime v0.19.7
 )
@@ -28,3 +29,5 @@ require (
 	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
 )
+
+replace github.com/openshift-kni/oran-o2ims/api/common => ../common
diff --git a/api/hardwaremanagement/v1alpha1/hardwareplugin_types.go b/api/hardwaremanagement/v1alpha1/hardwareplugin_types.go
index aea5ae4ab..e672e04f4 100644
--- a/api/hardwaremanagement/v1alpha1/hardwareplugin_types.go
+++ b/api/hardwaremanagement/v1alpha1/hardwareplugin_types.go
@@ -8,10 +8,9 @@ package v1alpha1
 
 import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
 
-// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
-// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.
+	"github.com/openshift-kni/oran-o2ims/api/common"
+)
 
 // ConditionTypes define the different types of conditions that will be set
 var ConditionTypes = struct {
@@ -33,12 +32,23 @@ var ConditionReasons = struct {
 
 // HardwarePluginSpec defines the desired state of HardwarePlugin
 type HardwarePluginSpec struct {
-	// Important: Run "make" to regenerate code after modifying this file
-
 	// ApiRoot is the root URL for the Hardware Plugin.
 	// +kubebuilder:validation:MinLength=1
 	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Hardware Plugin API root",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
 	ApiRoot string `json:"apiRoot"`
+
+	// CaBundleName references a config map that contains a set of custom CA certificates to be used when communicating
+	// with any outside HardwarePlugin server that has its TLS certificate signed by a non-public CA certificate.
+	// The config map is expected to contain a single file called 'ca-bundle.crt' containing all trusted CA certificates
+	// in PEM format.
+	// +optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Custom CA Certificates",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	CaBundleName *string `json:"caBundleName,omitempty"`
+
+	// AuthClientConfig defines the configurable client attributes required to access the OAuth2 authorization server
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="SMO OAuth Configuration"
+	AuthClientConfig *common.AuthClientConfig `json:"authClientConfig,omitempty"`
 }
 
 // HardwarePluginStatus defines the observed state of HardwarePlugin
diff --git a/api/hardwaremanagement/v1alpha1/zz_generated.deepcopy.go b/api/hardwaremanagement/v1alpha1/zz_generated.deepcopy.go
index 1eb25526a..1e6a165e7 100644
--- a/api/hardwaremanagement/v1alpha1/zz_generated.deepcopy.go
+++ b/api/hardwaremanagement/v1alpha1/zz_generated.deepcopy.go
@@ -11,6 +11,7 @@ SPDX-License-Identifier: Apache-2.0
 package v1alpha1
 
 import (
+	"github.com/openshift-kni/oran-o2ims/api/common"
 	"k8s.io/apimachinery/pkg/apis/meta/v1"
 	runtime "k8s.io/apimachinery/pkg/runtime"
 )
@@ -169,7 +170,7 @@ func (in *HardwarePlugin) DeepCopyInto(out *HardwarePlugin) {
 	*out = *in
 	out.TypeMeta = in.TypeMeta
 	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-	out.Spec = in.Spec
+	in.Spec.DeepCopyInto(&out.Spec)
 	in.Status.DeepCopyInto(&out.Status)
 }
 
@@ -226,6 +227,16 @@ func (in *HardwarePluginList) DeepCopyObject() runtime.Object {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *HardwarePluginSpec) DeepCopyInto(out *HardwarePluginSpec) {
 	*out = *in
+	if in.CaBundleName != nil {
+		in, out := &in.CaBundleName, &out.CaBundleName
+		*out = new(string)
+		**out = **in
+	}
+	if in.AuthClientConfig != nil {
+		in, out := &in.AuthClientConfig, &out.AuthClientConfig
+		*out = new(common.AuthClientConfig)
+		(*in).DeepCopyInto(*out)
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HardwarePluginSpec.
diff --git a/api/inventory/go.mod b/api/inventory/go.mod
index b18537a67..611f8967b 100644
--- a/api/inventory/go.mod
+++ b/api/inventory/go.mod
@@ -3,6 +3,7 @@ module github.com/openshift-kni/oran-o2ims/api/inventory
 go 1.22.0
 
 require (
+	github.com/openshift-kni/oran-o2ims/api/common v0.0.0-00010101000000-000000000000
 	k8s.io/apimachinery v0.31.8
 	sigs.k8s.io/controller-runtime v0.19.7
 )
@@ -28,3 +29,5 @@ require (
 	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
 )
+
+replace github.com/openshift-kni/oran-o2ims/api/common => ../common
diff --git a/api/inventory/v1alpha1/inventory_types.go b/api/inventory/v1alpha1/inventory_types.go
index b02bdb5ca..64997edff 100644
--- a/api/inventory/v1alpha1/inventory_types.go
+++ b/api/inventory/v1alpha1/inventory_types.go
@@ -8,6 +8,8 @@ package v1alpha1
 
 import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"github.com/openshift-kni/oran-o2ims/api/common"
 )
 
 // EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
@@ -50,19 +52,6 @@ type OAuthConfig struct {
 	ClientBindingClaim string `json:"clientBindingClaim"`
 }
 
-// TLSConfig defines the TLS specific attributes specific to the SMO and OAuth servers
-type TLSConfig struct {
-	// SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
-	// private key.  The secret is expected to contain a 'tls.key' and 'tls.crt' keys.  If the client is signed by
-	// intermediate CA certificate(s), then it is expected that the full chain is appended to the certificate file with
-	// the device certificate being first and the root CA being last.  It is expected that the certificate CN and DNS SAN configured be equal
-	// to the O2IMS DNS FQDN (e.g., o2ims.apps.<cluster domain name>).  This is to ensure that the certificate can be
-	// used as the ingress certificate as well as the outgoing client certificate.
-	//+optional
-	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="TLS certificate"
-	SecretName *string `json:"secretName"`
-}
-
 // SmoConfig defines the configurable attributes to represent the SMO instance
 type SmoConfig struct {
 	// URL represents the base URL of the SMO instance
@@ -80,7 +69,7 @@ type SmoConfig struct {
 	// TLS connection will be used.
 	//+optional
 	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Client TLS Configuration"
-	TLS *TLSConfig `json:"tls"`
+	TLS *common.TLSConfig `json:"tls"`
 }
 
 type ServerConfig struct {
@@ -126,7 +115,7 @@ type IngressConfig struct {
 	// the default IngressController will be used.
 	//+optional
 	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="TLS Configuration",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
-	TLS *TLSConfig `json:"tls,omitempty"`
+	TLS *common.TLSConfig `json:"tls,omitempty"`
 }
 
 // InventorySpec defines the desired state of Inventory
diff --git a/api/inventory/v1alpha1/zz_generated.deepcopy.go b/api/inventory/v1alpha1/zz_generated.deepcopy.go
index f5b2c3dfc..11bfed1d8 100644
--- a/api/inventory/v1alpha1/zz_generated.deepcopy.go
+++ b/api/inventory/v1alpha1/zz_generated.deepcopy.go
@@ -11,6 +11,7 @@ SPDX-License-Identifier: Apache-2.0
 package v1alpha1
 
 import (
+	"github.com/openshift-kni/oran-o2ims/api/common"
 	"k8s.io/apimachinery/pkg/apis/meta/v1"
 	runtime "k8s.io/apimachinery/pkg/runtime"
 )
@@ -73,7 +74,7 @@ func (in *IngressConfig) DeepCopyInto(out *IngressConfig) {
 	}
 	if in.TLS != nil {
 		in, out := &in.TLS, &out.TLS
-		*out = new(TLSConfig)
+		*out = new(common.TLSConfig)
 		(*in).DeepCopyInto(*out)
 	}
 }
@@ -312,7 +313,7 @@ func (in *SmoConfig) DeepCopyInto(out *SmoConfig) {
 	}
 	if in.TLS != nil {
 		in, out := &in.TLS, &out.TLS
-		*out = new(TLSConfig)
+		*out = new(common.TLSConfig)
 		(*in).DeepCopyInto(*out)
 	}
 }
@@ -327,26 +328,6 @@ func (in *SmoConfig) DeepCopy() *SmoConfig {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *TLSConfig) DeepCopyInto(out *TLSConfig) {
-	*out = *in
-	if in.SecretName != nil {
-		in, out := &in.SecretName, &out.SecretName
-		*out = new(string)
-		**out = **in
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig.
-func (in *TLSConfig) DeepCopy() *TLSConfig {
-	if in == nil {
-		return nil
-	}
-	out := new(TLSConfig)
-	in.DeepCopyInto(out)
-	return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *UsedServerConfig) DeepCopyInto(out *UsedServerConfig) {
 	*out = *in
diff --git a/bundle/manifests/o2ims-hardwaremanagement.oran.openshift.io_hardwareplugins.yaml b/bundle/manifests/o2ims-hardwaremanagement.oran.openshift.io_hardwareplugins.yaml
index e47720d65..42d6f7658 100644
--- a/bundle/manifests/o2ims-hardwaremanagement.oran.openshift.io_hardwareplugins.yaml
+++ b/bundle/manifests/o2ims-hardwaremanagement.oran.openshift.io_hardwareplugins.yaml
@@ -43,6 +43,82 @@ spec:
                 description: ApiRoot is the root URL for the Hardware Plugin.
                 minLength: 1
                 type: string
+              authClientConfig:
+                description: AuthClientConfig defines the configurable client attributes
+                  required to access the OAuth2 authorization server
+                properties:
+                  basicAuthSecret:
+                    description: |-
+                      BasicAuthSecret represents the name of a secret (in the current namespace) containing the username
+                      and password for Basic authentication. The secret is expected to contain 'username' and 'password' keys.
+                      This field is required when Type is set to "Basic".
+                    type: string
+                  oauthConfig:
+                    description: |-
+                      OAuthConfig holds the configuration for OAuth2-based authentication, including the authorization server
+                      URL, token endpoint, and client credentials. This field is required when Type is set to "OAuth".
+                    properties:
+                      clientSecretName:
+                        description: |-
+                          ClientSecretName represents the name of a secret (in the current namespace) which contains the client-id and
+                          client-secret values used by the OAuth client.
+                        type: string
+                      scopes:
+                        description: |-
+                          Scopes represents the OAuth scope values to request when acquiring a token.  Typically, this should be set to
+                          "openid" in addition to any other scopes that the SMO specifically requires (e.g., "roles", "groups", etc...) to
+                          authorize our requests
+                        items:
+                          type: string
+                        type: array
+                      tokenEndpoint:
+                        description: |-
+                          TokenEndpoint represents the API endpoint used to acquire a token (e.g., /protocol/openid-connect/token) which
+                          will be appended to the base URL to form the full URL
+                        type: string
+                      url:
+                        description: URL represents the base URL of the authorization
+                          server. (e.g., https://keycloak.example.com/realms/oran)
+                        type: string
+                    required:
+                    - clientSecretName
+                    - scopes
+                    - tokenEndpoint
+                    - url
+                    type: object
+                  tlsConfig:
+                    description: |-
+                      TLSConfig specifies the TLS configuration for secure communication, including the certificate and private
+                      key. This field is optional and can be used with any authentication type to enable TLS for the connection.
+                    properties:
+                      secretName:
+                        description: |-
+                          SecretName specifies the name of a secret (in the current namespace) containing an X.509 certificate and
+                          private key. The secret must include 'tls.key' and 'tls.crt' keys. If the certificate is signed by
+                          intermediate CA(s), the full certificate chain should be included in the certificate file, with the
+                          leaf certificate first and the root CA last. The certificate's Common Name (CN) or Subject Alternative
+                          Name (SAN) should align with the service's fully qualified domain name to support both ingress and
+                          outgoing client certificate use cases.
+                        type: string
+                    type: object
+                  type:
+                    description: Type specifies the authentication type to be used
+                      (e.g., ServiceAccount, Basic, or OAuth).
+                    enum:
+                    - ServiceAccount
+                    - Basic
+                    - OAuth
+                    type: string
+                required:
+                - type
+                type: object
+              caBundleName:
+                description: |-
+                  CaBundleName references a config map that contains a set of custom CA certificates to be used when communicating
+                  with any outside HardwarePlugin server that has its TLS certificate signed by a non-public CA certificate.
+                  The config map is expected to contain a single file called 'ca-bundle.crt' containing all trusted CA certificates
+                  in PEM format.
+                type: string
             required:
             - apiRoot
             type: object
diff --git a/bundle/manifests/o2ims.oran.openshift.io_inventories.yaml b/bundle/manifests/o2ims.oran.openshift.io_inventories.yaml
index 5d2a5e30e..dde1d2963 100644
--- a/bundle/manifests/o2ims.oran.openshift.io_inventories.yaml
+++ b/bundle/manifests/o2ims.oran.openshift.io_inventories.yaml
@@ -86,12 +86,12 @@ spec:
                     properties:
                       secretName:
                         description: |-
-                          SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
-                          private key.  The secret is expected to contain a 'tls.key' and 'tls.crt' keys.  If the client is signed by
-                          intermediate CA certificate(s), then it is expected that the full chain is appended to the certificate file with
-                          the device certificate being first and the root CA being last.  It is expected that the certificate CN and DNS SAN configured be equal
-                          to the O2IMS DNS FQDN (e.g., o2ims.apps.<cluster domain name>).  This is to ensure that the certificate can be
-                          used as the ingress certificate as well as the outgoing client certificate.
+                          SecretName specifies the name of a secret (in the current namespace) containing an X.509 certificate and
+                          private key. The secret must include 'tls.key' and 'tls.crt' keys. If the certificate is signed by
+                          intermediate CA(s), the full certificate chain should be included in the certificate file, with the
+                          leaf certificate first and the root CA last. The certificate's Common Name (CN) or Subject Alternative
+                          Name (SAN) should align with the service's fully qualified domain name to support both ingress and
+                          outgoing client certificate use cases.
                         type: string
                     type: object
                 type: object
@@ -173,12 +173,12 @@ spec:
                     properties:
                       secretName:
                         description: |-
-                          SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
-                          private key.  The secret is expected to contain a 'tls.key' and 'tls.crt' keys.  If the client is signed by
-                          intermediate CA certificate(s), then it is expected that the full chain is appended to the certificate file with
-                          the device certificate being first and the root CA being last.  It is expected that the certificate CN and DNS SAN configured be equal
-                          to the O2IMS DNS FQDN (e.g., o2ims.apps.<cluster domain name>).  This is to ensure that the certificate can be
-                          used as the ingress certificate as well as the outgoing client certificate.
+                          SecretName specifies the name of a secret (in the current namespace) containing an X.509 certificate and
+                          private key. The secret must include 'tls.key' and 'tls.crt' keys. If the certificate is signed by
+                          intermediate CA(s), the full certificate chain should be included in the certificate file, with the
+                          leaf certificate first and the root CA last. The certificate's Common Name (CN) or Subject Alternative
+                          Name (SAN) should align with the service's fully qualified domain name to support both ingress and
+                          outgoing client certificate use cases.
                         type: string
                     type: object
                   url:
diff --git a/bundle/manifests/oran-o2ims.clusterserviceversion.yaml b/bundle/manifests/oran-o2ims.clusterserviceversion.yaml
index 31a24e23a..b647826ec 100644
--- a/bundle/manifests/oran-o2ims.clusterserviceversion.yaml
+++ b/bundle/manifests/oran-o2ims.clusterserviceversion.yaml
@@ -868,13 +868,13 @@ spec:
         x-descriptors:
         - urn:alm:descriptor:com.tectonic.ui:text
       - description: |-
-          SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
-          private key.  The secret is expected to contain a 'tls.key' and 'tls.crt' keys.  If the client is signed by
-          intermediate CA certificate(s), then it is expected that the full chain is appended to the certificate file with
-          the device certificate being first and the root CA being last.  It is expected that the certificate CN and DNS SAN configured be equal
-          to the O2IMS DNS FQDN (e.g., o2ims.apps.<cluster domain name>).  This is to ensure that the certificate can be
-          used as the ingress certificate as well as the outgoing client certificate.
-        displayName: TLS certificate
+          SecretName specifies the name of a secret (in the current namespace) containing an X.509 certificate and
+          private key. The secret must include 'tls.key' and 'tls.crt' keys. If the certificate is signed by
+          intermediate CA(s), the full certificate chain should be included in the certificate file, with the
+          leaf certificate first and the root CA last. The certificate's Common Name (CN) or Subject Alternative
+          Name (SAN) should align with the service's fully qualified domain name to support both ingress and
+          outgoing client certificate use cases.
+        displayName: TLS Certificate
         path: ingress.tls.secretName
       - description: ProvisioningServerConfig contains the configuration for the provisioning
           server.
@@ -959,13 +959,13 @@ spec:
         displayName: Client TLS Configuration
         path: smo.tls
       - description: |-
-          SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
-          private key.  The secret is expected to contain a 'tls.key' and 'tls.crt' keys.  If the client is signed by
-          intermediate CA certificate(s), then it is expected that the full chain is appended to the certificate file with
-          the device certificate being first and the root CA being last.  It is expected that the certificate CN and DNS SAN configured be equal
-          to the O2IMS DNS FQDN (e.g., o2ims.apps.<cluster domain name>).  This is to ensure that the certificate can be
-          used as the ingress certificate as well as the outgoing client certificate.
-        displayName: TLS certificate
+          SecretName specifies the name of a secret (in the current namespace) containing an X.509 certificate and
+          private key. The secret must include 'tls.key' and 'tls.crt' keys. If the certificate is signed by
+          intermediate CA(s), the full certificate chain should be included in the certificate file, with the
+          leaf certificate first and the root CA last. The certificate's Common Name (CN) or Subject Alternative
+          Name (SAN) should align with the service's fully qualified domain name to support both ingress and
+          outgoing client certificate use cases.
+        displayName: TLS Certificate
         path: smo.tls.secretName
       - description: URL represents the base URL of the SMO instance
         displayName: SMO URL
diff --git a/config/crd/bases/o2ims-hardwaremanagement.oran.openshift.io_hardwareplugins.yaml b/config/crd/bases/o2ims-hardwaremanagement.oran.openshift.io_hardwareplugins.yaml
index 397f30221..a7fbf8545 100644
--- a/config/crd/bases/o2ims-hardwaremanagement.oran.openshift.io_hardwareplugins.yaml
+++ b/config/crd/bases/o2ims-hardwaremanagement.oran.openshift.io_hardwareplugins.yaml
@@ -43,6 +43,82 @@ spec:
                 description: ApiRoot is the root URL for the Hardware Plugin.
                 minLength: 1
                 type: string
+              authClientConfig:
+                description: AuthClientConfig defines the configurable client attributes
+                  required to access the OAuth2 authorization server
+                properties:
+                  basicAuthSecret:
+                    description: |-
+                      BasicAuthSecret represents the name of a secret (in the current namespace) containing the username
+                      and password for Basic authentication. The secret is expected to contain 'username' and 'password' keys.
+                      This field is required when Type is set to "Basic".
+                    type: string
+                  oauthConfig:
+                    description: |-
+                      OAuthConfig holds the configuration for OAuth2-based authentication, including the authorization server
+                      URL, token endpoint, and client credentials. This field is required when Type is set to "OAuth".
+                    properties:
+                      clientSecretName:
+                        description: |-
+                          ClientSecretName represents the name of a secret (in the current namespace) which contains the client-id and
+                          client-secret values used by the OAuth client.
+                        type: string
+                      scopes:
+                        description: |-
+                          Scopes represents the OAuth scope values to request when acquiring a token.  Typically, this should be set to
+                          "openid" in addition to any other scopes that the SMO specifically requires (e.g., "roles", "groups", etc...) to
+                          authorize our requests
+                        items:
+                          type: string
+                        type: array
+                      tokenEndpoint:
+                        description: |-
+                          TokenEndpoint represents the API endpoint used to acquire a token (e.g., /protocol/openid-connect/token) which
+                          will be appended to the base URL to form the full URL
+                        type: string
+                      url:
+                        description: URL represents the base URL of the authorization
+                          server. (e.g., https://keycloak.example.com/realms/oran)
+                        type: string
+                    required:
+                    - clientSecretName
+                    - scopes
+                    - tokenEndpoint
+                    - url
+                    type: object
+                  tlsConfig:
+                    description: |-
+                      TLSConfig specifies the TLS configuration for secure communication, including the certificate and private
+                      key. This field is optional and can be used with any authentication type to enable TLS for the connection.
+                    properties:
+                      secretName:
+                        description: |-
+                          SecretName specifies the name of a secret (in the current namespace) containing an X.509 certificate and
+                          private key. The secret must include 'tls.key' and 'tls.crt' keys. If the certificate is signed by
+                          intermediate CA(s), the full certificate chain should be included in the certificate file, with the
+                          leaf certificate first and the root CA last. The certificate's Common Name (CN) or Subject Alternative
+                          Name (SAN) should align with the service's fully qualified domain name to support both ingress and
+                          outgoing client certificate use cases.
+                        type: string
+                    type: object
+                  type:
+                    description: Type specifies the authentication type to be used
+                      (e.g., ServiceAccount, Basic, or OAuth).
+                    enum:
+                    - ServiceAccount
+                    - Basic
+                    - OAuth
+                    type: string
+                required:
+                - type
+                type: object
+              caBundleName:
+                description: |-
+                  CaBundleName references a config map that contains a set of custom CA certificates to be used when communicating
+                  with any outside HardwarePlugin server that has its TLS certificate signed by a non-public CA certificate.
+                  The config map is expected to contain a single file called 'ca-bundle.crt' containing all trusted CA certificates
+                  in PEM format.
+                type: string
             required:
             - apiRoot
             type: object
diff --git a/config/crd/bases/o2ims.oran.openshift.io_inventories.yaml b/config/crd/bases/o2ims.oran.openshift.io_inventories.yaml
index 8e69ab57e..457127d74 100644
--- a/config/crd/bases/o2ims.oran.openshift.io_inventories.yaml
+++ b/config/crd/bases/o2ims.oran.openshift.io_inventories.yaml
@@ -86,12 +86,12 @@ spec:
                     properties:
                       secretName:
                         description: |-
-                          SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
-                          private key.  The secret is expected to contain a 'tls.key' and 'tls.crt' keys.  If the client is signed by
-                          intermediate CA certificate(s), then it is expected that the full chain is appended to the certificate file with
-                          the device certificate being first and the root CA being last.  It is expected that the certificate CN and DNS SAN configured be equal
-                          to the O2IMS DNS FQDN (e.g., o2ims.apps.<cluster domain name>).  This is to ensure that the certificate can be
-                          used as the ingress certificate as well as the outgoing client certificate.
+                          SecretName specifies the name of a secret (in the current namespace) containing an X.509 certificate and
+                          private key. The secret must include 'tls.key' and 'tls.crt' keys. If the certificate is signed by
+                          intermediate CA(s), the full certificate chain should be included in the certificate file, with the
+                          leaf certificate first and the root CA last. The certificate's Common Name (CN) or Subject Alternative
+                          Name (SAN) should align with the service's fully qualified domain name to support both ingress and
+                          outgoing client certificate use cases.
                         type: string
                     type: object
                 type: object
@@ -173,12 +173,12 @@ spec:
                     properties:
                       secretName:
                         description: |-
-                          SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
-                          private key.  The secret is expected to contain a 'tls.key' and 'tls.crt' keys.  If the client is signed by
-                          intermediate CA certificate(s), then it is expected that the full chain is appended to the certificate file with
-                          the device certificate being first and the root CA being last.  It is expected that the certificate CN and DNS SAN configured be equal
-                          to the O2IMS DNS FQDN (e.g., o2ims.apps.<cluster domain name>).  This is to ensure that the certificate can be
-                          used as the ingress certificate as well as the outgoing client certificate.
+                          SecretName specifies the name of a secret (in the current namespace) containing an X.509 certificate and
+                          private key. The secret must include 'tls.key' and 'tls.crt' keys. If the certificate is signed by
+                          intermediate CA(s), the full certificate chain should be included in the certificate file, with the
+                          leaf certificate first and the root CA last. The certificate's Common Name (CN) or Subject Alternative
+                          Name (SAN) should align with the service's fully qualified domain name to support both ingress and
+                          outgoing client certificate use cases.
                         type: string
                     type: object
                   url:
diff --git a/config/manifests/bases/oran-o2ims.clusterserviceversion.yaml b/config/manifests/bases/oran-o2ims.clusterserviceversion.yaml
index 7623fc845..35cf3070e 100644
--- a/config/manifests/bases/oran-o2ims.clusterserviceversion.yaml
+++ b/config/manifests/bases/oran-o2ims.clusterserviceversion.yaml
@@ -262,13 +262,13 @@ spec:
         x-descriptors:
         - urn:alm:descriptor:com.tectonic.ui:text
       - description: |-
-          SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
-          private key.  The secret is expected to contain a 'tls.key' and 'tls.crt' keys.  If the client is signed by
-          intermediate CA certificate(s), then it is expected that the full chain is appended to the certificate file with
-          the device certificate being first and the root CA being last.  It is expected that the certificate CN and DNS SAN configured be equal
-          to the O2IMS DNS FQDN (e.g., o2ims.apps.<cluster domain name>).  This is to ensure that the certificate can be
-          used as the ingress certificate as well as the outgoing client certificate.
-        displayName: TLS certificate
+          SecretName specifies the name of a secret (in the current namespace) containing an X.509 certificate and
+          private key. The secret must include 'tls.key' and 'tls.crt' keys. If the certificate is signed by
+          intermediate CA(s), the full certificate chain should be included in the certificate file, with the
+          leaf certificate first and the root CA last. The certificate's Common Name (CN) or Subject Alternative
+          Name (SAN) should align with the service's fully qualified domain name to support both ingress and
+          outgoing client certificate use cases.
+        displayName: TLS Certificate
         path: ingress.tls.secretName
       - description: ProvisioningServerConfig contains the configuration for the provisioning
           server.
@@ -353,13 +353,13 @@ spec:
         displayName: Client TLS Configuration
         path: smo.tls
       - description: |-
-          SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
-          private key.  The secret is expected to contain a 'tls.key' and 'tls.crt' keys.  If the client is signed by
-          intermediate CA certificate(s), then it is expected that the full chain is appended to the certificate file with
-          the device certificate being first and the root CA being last.  It is expected that the certificate CN and DNS SAN configured be equal
-          to the O2IMS DNS FQDN (e.g., o2ims.apps.<cluster domain name>).  This is to ensure that the certificate can be
-          used as the ingress certificate as well as the outgoing client certificate.
-        displayName: TLS certificate
+          SecretName specifies the name of a secret (in the current namespace) containing an X.509 certificate and
+          private key. The secret must include 'tls.key' and 'tls.crt' keys. If the certificate is signed by
+          intermediate CA(s), the full certificate chain should be included in the certificate file, with the
+          leaf certificate first and the root CA last. The certificate's Common Name (CN) or Subject Alternative
+          Name (SAN) should align with the service's fully qualified domain name to support both ingress and
+          outgoing client certificate use cases.
+        displayName: TLS Certificate
         path: smo.tls.secretName
       - description: URL represents the base URL of the SMO instance
         displayName: SMO URL
diff --git a/go.mod b/go.mod
index 43db47b05..353532097 100644
--- a/go.mod
+++ b/go.mod
@@ -129,6 +129,7 @@ require (
 	github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
 	github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
 	github.com/oklog/ulid v1.3.1 // indirect
+	github.com/openshift-kni/oran-o2ims/api/common v0.0.0-00010101000000-000000000000 // indirect
 	github.com/openshift/assisted-service/models v0.0.0 // indirect
 	github.com/openshift/hive/apis v0.0.0-20240306163002-9c5806a63531 // indirect
 	github.com/perimeterx/marshmallow v1.1.5 // indirect
@@ -192,11 +193,12 @@ require (
 	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
 )
 
-replace github.com/openshift-kni/oran-o2ims/api/hardwaremanagement => ./api/hardwaremanagement
-
-replace github.com/openshift-kni/oran-o2ims/api/inventory => ./api/inventory
-
-replace github.com/openshift-kni/oran-o2ims/api/provisioning => ./api/provisioning
+replace (
+	github.com/openshift-kni/oran-o2ims/api/common => ./api/common
+	github.com/openshift-kni/oran-o2ims/api/hardwaremanagement => ./api/hardwaremanagement
+	github.com/openshift-kni/oran-o2ims/api/inventory => ./api/inventory
+	github.com/openshift-kni/oran-o2ims/api/provisioning => ./api/provisioning
+)
 
 // From the mergo project's README: "If the vanity URL is causing issues in
 // your project due to a dependency pulling Mergo - it isn't a direct
diff --git a/vendor/github.com/openshift-kni/oran-o2ims/api/common/common_types.go b/vendor/github.com/openshift-kni/oran-o2ims/api/common/common_types.go
new file mode 100644
index 000000000..2168e5efb
--- /dev/null
+++ b/vendor/github.com/openshift-kni/oran-o2ims/api/common/common_types.go
@@ -0,0 +1,100 @@
+/*
+SPDX-FileCopyrightText: Red Hat
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package common
+
+// +genclient
+
+// +kubebuilder:object:generate=true
+// TLSConfig defines the configuration for TLS-specific attributes.
+type TLSConfig struct {
+	// SecretName specifies the name of a secret (in the current namespace) containing an X.509 certificate and
+	// private key. The secret must include 'tls.key' and 'tls.crt' keys. If the certificate is signed by
+	// intermediate CA(s), the full certificate chain should be included in the certificate file, with the
+	// leaf certificate first and the root CA last. The certificate's Common Name (CN) or Subject Alternative
+	// Name (SAN) should align with the service's fully qualified domain name to support both ingress and
+	// outgoing client certificate use cases.
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="TLS Certificate"
+	SecretName *string `json:"secretName"`
+}
+
+// +kubebuilder:object:generate=true
+// OAuthClientConfig defines the configurable client attributes that represent the authentication mechanism.  This is currently
+// expected to be a way to acquire a token from an OAuth2 server.
+type OAuthClientConfig struct {
+	// URL represents the base URL of the authorization server. (e.g., https://keycloak.example.com/realms/oran)
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth URL",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	URL string `json:"url"`
+	// TokenEndpoint represents the API endpoint used to acquire a token (e.g., /protocol/openid-connect/token) which
+	// will be appended to the base URL to form the full URL
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Token Endpoint",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	TokenEndpoint string `json:"tokenEndpoint"`
+	// ClientSecretName represents the name of a secret (in the current namespace) which contains the client-id and
+	// client-secret values used by the OAuth client.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Client Secret",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	ClientSecretName string `json:"clientSecretName"`
+	// Scopes represents the OAuth scope values to request when acquiring a token.  Typically, this should be set to
+	// "openid" in addition to any other scopes that the SMO specifically requires (e.g., "roles", "groups", etc...) to
+	// authorize our requests
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Scopes",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	Scopes []string `json:"scopes"`
+}
+
+// +kubebuilder:object:generate=true
+// AuthType defines the authorization type used for authentication.
+type AuthType string
+
+const (
+	// ServiceAccount represents authentication using a Kubernetes ServiceAccount token. This method assumes
+	// the server provides a service running within the same Kubernetes cluster and leverages a ServiceAccount
+	// to authenticate requests. It is used for internal cluster communication, where the client presents a
+	// JWT token issued by the cluster's Kubernetes API server.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="ServiceAccount Authentication"
+	ServiceAccount AuthType = "ServiceAccount"
+
+	// Basic represents authentication using HTTP Basic Authentication. This method uses a username and password
+	// combination to authenticate requests, typically encoded in the Authorization header of HTTP requests.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Basic Authentication"
+	Basic AuthType = "Basic"
+
+	// OAuth represents authentication using an OAuth2-based mechanism. This method involves acquiring a token
+	// from an OAuth2 server using the client_credentials grant type, which is then used to authenticate
+	// requests, typically via a Bearer token in the Authorization header. Only the client_credentials grant
+	// type is supported. Configuration details for OAuth, including the authorization server URL and client
+	// credentials, are specified in the OAuthConfig struct.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Authentication"
+	OAuth AuthType = "OAuth"
+)
+
+// +kubebuilder:object:generate=true
+// AuthConfig defines the configuration for different authentication types.
+// This struct encapsulates the settings required for ServiceAccount, Basic, and OAuth authentication mechanisms.
+type AuthClientConfig struct {
+	// Type specifies the authentication type to be used (e.g., ServiceAccount, Basic, or OAuth).
+	//+kubebuilder:validation:Enum=ServiceAccount;Basic;OAuth
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Authentication Type",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:select:ServiceAccount","urn:alm:descriptor:com.tectonic.ui:select:Basic","urn:alm:descriptor:com.tectonic.ui:select:OAuth"}
+	Type AuthType `json:"type"`
+
+	// BasicAuthSecret represents the name of a secret (in the current namespace) containing the username
+	// and password for Basic authentication. The secret is expected to contain 'username' and 'password' keys.
+	// This field is required when Type is set to "Basic".
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Basic Auth Secret",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	BasicAuthSecret *string `json:"basicAuthSecret,omitempty"`
+
+	// OAuthConfig holds the configuration for OAuth2-based authentication, including the authorization server
+	// URL, token endpoint, and client credentials. This field is required when Type is set to "OAuth".
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Configuration"
+	OAuthClientConfig *OAuthClientConfig `json:"oauthConfig,omitempty"`
+
+	// TLSConfig specifies the TLS configuration for secure communication, including the certificate and private
+	// key. This field is optional and can be used with any authentication type to enable TLS for the connection.
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="TLS Configuration"
+	TLSConfig *TLSConfig `json:"tlsConfig,omitempty"`
+}
diff --git a/vendor/github.com/openshift-kni/oran-o2ims/api/common/zz_generated.deepcopy.go b/vendor/github.com/openshift-kni/oran-o2ims/api/common/zz_generated.deepcopy.go
new file mode 100644
index 000000000..5d5076870
--- /dev/null
+++ b/vendor/github.com/openshift-kni/oran-o2ims/api/common/zz_generated.deepcopy.go
@@ -0,0 +1,81 @@
+//go:build !ignore_autogenerated
+
+/*
+SPDX-FileCopyrightText: Red Hat
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package common
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AuthClientConfig) DeepCopyInto(out *AuthClientConfig) {
+	*out = *in
+	if in.BasicAuthSecret != nil {
+		in, out := &in.BasicAuthSecret, &out.BasicAuthSecret
+		*out = new(string)
+		**out = **in
+	}
+	if in.OAuthClientConfig != nil {
+		in, out := &in.OAuthClientConfig, &out.OAuthClientConfig
+		*out = new(OAuthClientConfig)
+		(*in).DeepCopyInto(*out)
+	}
+	if in.TLSConfig != nil {
+		in, out := &in.TLSConfig, &out.TLSConfig
+		*out = new(TLSConfig)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthClientConfig.
+func (in *AuthClientConfig) DeepCopy() *AuthClientConfig {
+	if in == nil {
+		return nil
+	}
+	out := new(AuthClientConfig)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *OAuthClientConfig) DeepCopyInto(out *OAuthClientConfig) {
+	*out = *in
+	if in.Scopes != nil {
+		in, out := &in.Scopes, &out.Scopes
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OAuthClientConfig.
+func (in *OAuthClientConfig) DeepCopy() *OAuthClientConfig {
+	if in == nil {
+		return nil
+	}
+	out := new(OAuthClientConfig)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TLSConfig) DeepCopyInto(out *TLSConfig) {
+	*out = *in
+	if in.SecretName != nil {
+		in, out := &in.SecretName, &out.SecretName
+		*out = new(string)
+		**out = **in
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig.
+func (in *TLSConfig) DeepCopy() *TLSConfig {
+	if in == nil {
+		return nil
+	}
+	out := new(TLSConfig)
+	in.DeepCopyInto(out)
+	return out
+}
diff --git a/vendor/github.com/openshift-kni/oran-o2ims/api/hardwaremanagement/v1alpha1/hardwareplugin_types.go b/vendor/github.com/openshift-kni/oran-o2ims/api/hardwaremanagement/v1alpha1/hardwareplugin_types.go
index aea5ae4ab..e672e04f4 100644
--- a/vendor/github.com/openshift-kni/oran-o2ims/api/hardwaremanagement/v1alpha1/hardwareplugin_types.go
+++ b/vendor/github.com/openshift-kni/oran-o2ims/api/hardwaremanagement/v1alpha1/hardwareplugin_types.go
@@ -8,10 +8,9 @@ package v1alpha1
 
 import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
 
-// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
-// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.
+	"github.com/openshift-kni/oran-o2ims/api/common"
+)
 
 // ConditionTypes define the different types of conditions that will be set
 var ConditionTypes = struct {
@@ -33,12 +32,23 @@ var ConditionReasons = struct {
 
 // HardwarePluginSpec defines the desired state of HardwarePlugin
 type HardwarePluginSpec struct {
-	// Important: Run "make" to regenerate code after modifying this file
-
 	// ApiRoot is the root URL for the Hardware Plugin.
 	// +kubebuilder:validation:MinLength=1
 	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Hardware Plugin API root",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
 	ApiRoot string `json:"apiRoot"`
+
+	// CaBundleName references a config map that contains a set of custom CA certificates to be used when communicating
+	// with any outside HardwarePlugin server that has its TLS certificate signed by a non-public CA certificate.
+	// The config map is expected to contain a single file called 'ca-bundle.crt' containing all trusted CA certificates
+	// in PEM format.
+	// +optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Custom CA Certificates",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	CaBundleName *string `json:"caBundleName,omitempty"`
+
+	// AuthClientConfig defines the configurable client attributes required to access the OAuth2 authorization server
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="SMO OAuth Configuration"
+	AuthClientConfig *common.AuthClientConfig `json:"authClientConfig,omitempty"`
 }
 
 // HardwarePluginStatus defines the observed state of HardwarePlugin
diff --git a/vendor/github.com/openshift-kni/oran-o2ims/api/hardwaremanagement/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/openshift-kni/oran-o2ims/api/hardwaremanagement/v1alpha1/zz_generated.deepcopy.go
index 1eb25526a..1e6a165e7 100644
--- a/vendor/github.com/openshift-kni/oran-o2ims/api/hardwaremanagement/v1alpha1/zz_generated.deepcopy.go
+++ b/vendor/github.com/openshift-kni/oran-o2ims/api/hardwaremanagement/v1alpha1/zz_generated.deepcopy.go
@@ -11,6 +11,7 @@ SPDX-License-Identifier: Apache-2.0
 package v1alpha1
 
 import (
+	"github.com/openshift-kni/oran-o2ims/api/common"
 	"k8s.io/apimachinery/pkg/apis/meta/v1"
 	runtime "k8s.io/apimachinery/pkg/runtime"
 )
@@ -169,7 +170,7 @@ func (in *HardwarePlugin) DeepCopyInto(out *HardwarePlugin) {
 	*out = *in
 	out.TypeMeta = in.TypeMeta
 	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-	out.Spec = in.Spec
+	in.Spec.DeepCopyInto(&out.Spec)
 	in.Status.DeepCopyInto(&out.Status)
 }
 
@@ -226,6 +227,16 @@ func (in *HardwarePluginList) DeepCopyObject() runtime.Object {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *HardwarePluginSpec) DeepCopyInto(out *HardwarePluginSpec) {
 	*out = *in
+	if in.CaBundleName != nil {
+		in, out := &in.CaBundleName, &out.CaBundleName
+		*out = new(string)
+		**out = **in
+	}
+	if in.AuthClientConfig != nil {
+		in, out := &in.AuthClientConfig, &out.AuthClientConfig
+		*out = new(common.AuthClientConfig)
+		(*in).DeepCopyInto(*out)
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HardwarePluginSpec.
diff --git a/vendor/github.com/openshift-kni/oran-o2ims/api/inventory/v1alpha1/inventory_types.go b/vendor/github.com/openshift-kni/oran-o2ims/api/inventory/v1alpha1/inventory_types.go
index b02bdb5ca..64997edff 100644
--- a/vendor/github.com/openshift-kni/oran-o2ims/api/inventory/v1alpha1/inventory_types.go
+++ b/vendor/github.com/openshift-kni/oran-o2ims/api/inventory/v1alpha1/inventory_types.go
@@ -8,6 +8,8 @@ package v1alpha1
 
 import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"github.com/openshift-kni/oran-o2ims/api/common"
 )
 
 // EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
@@ -50,19 +52,6 @@ type OAuthConfig struct {
 	ClientBindingClaim string `json:"clientBindingClaim"`
 }
 
-// TLSConfig defines the TLS specific attributes specific to the SMO and OAuth servers
-type TLSConfig struct {
-	// SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
-	// private key.  The secret is expected to contain a 'tls.key' and 'tls.crt' keys.  If the client is signed by
-	// intermediate CA certificate(s), then it is expected that the full chain is appended to the certificate file with
-	// the device certificate being first and the root CA being last.  It is expected that the certificate CN and DNS SAN configured be equal
-	// to the O2IMS DNS FQDN (e.g., o2ims.apps.<cluster domain name>).  This is to ensure that the certificate can be
-	// used as the ingress certificate as well as the outgoing client certificate.
-	//+optional
-	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="TLS certificate"
-	SecretName *string `json:"secretName"`
-}
-
 // SmoConfig defines the configurable attributes to represent the SMO instance
 type SmoConfig struct {
 	// URL represents the base URL of the SMO instance
@@ -80,7 +69,7 @@ type SmoConfig struct {
 	// TLS connection will be used.
 	//+optional
 	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Client TLS Configuration"
-	TLS *TLSConfig `json:"tls"`
+	TLS *common.TLSConfig `json:"tls"`
 }
 
 type ServerConfig struct {
@@ -126,7 +115,7 @@ type IngressConfig struct {
 	// the default IngressController will be used.
 	//+optional
 	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="TLS Configuration",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
-	TLS *TLSConfig `json:"tls,omitempty"`
+	TLS *common.TLSConfig `json:"tls,omitempty"`
 }
 
 // InventorySpec defines the desired state of Inventory
diff --git a/vendor/github.com/openshift-kni/oran-o2ims/api/inventory/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/openshift-kni/oran-o2ims/api/inventory/v1alpha1/zz_generated.deepcopy.go
index f5b2c3dfc..11bfed1d8 100644
--- a/vendor/github.com/openshift-kni/oran-o2ims/api/inventory/v1alpha1/zz_generated.deepcopy.go
+++ b/vendor/github.com/openshift-kni/oran-o2ims/api/inventory/v1alpha1/zz_generated.deepcopy.go
@@ -11,6 +11,7 @@ SPDX-License-Identifier: Apache-2.0
 package v1alpha1
 
 import (
+	"github.com/openshift-kni/oran-o2ims/api/common"
 	"k8s.io/apimachinery/pkg/apis/meta/v1"
 	runtime "k8s.io/apimachinery/pkg/runtime"
 )
@@ -73,7 +74,7 @@ func (in *IngressConfig) DeepCopyInto(out *IngressConfig) {
 	}
 	if in.TLS != nil {
 		in, out := &in.TLS, &out.TLS
-		*out = new(TLSConfig)
+		*out = new(common.TLSConfig)
 		(*in).DeepCopyInto(*out)
 	}
 }
@@ -312,7 +313,7 @@ func (in *SmoConfig) DeepCopyInto(out *SmoConfig) {
 	}
 	if in.TLS != nil {
 		in, out := &in.TLS, &out.TLS
-		*out = new(TLSConfig)
+		*out = new(common.TLSConfig)
 		(*in).DeepCopyInto(*out)
 	}
 }
@@ -327,26 +328,6 @@ func (in *SmoConfig) DeepCopy() *SmoConfig {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *TLSConfig) DeepCopyInto(out *TLSConfig) {
-	*out = *in
-	if in.SecretName != nil {
-		in, out := &in.SecretName, &out.SecretName
-		*out = new(string)
-		**out = **in
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig.
-func (in *TLSConfig) DeepCopy() *TLSConfig {
-	if in == nil {
-		return nil
-	}
-	out := new(TLSConfig)
-	in.DeepCopyInto(out)
-	return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *UsedServerConfig) DeepCopyInto(out *UsedServerConfig) {
 	*out = *in
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 33737afaa..817fdcdce 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -478,6 +478,9 @@ github.com/openshift-kni/oran-hwmgr-plugin/api/hwmgr-plugin/v1alpha1
 # github.com/openshift-kni/oran-hwmgr-plugin/pkg/inventory-client v0.0.0-20250125003258-ee379f966a62
 ## explicit; go 1.22
 github.com/openshift-kni/oran-hwmgr-plugin/pkg/inventory-client/generated
+# github.com/openshift-kni/oran-o2ims/api/common v0.0.0-00010101000000-000000000000 => ./api/common
+## explicit; go 1.22.0
+github.com/openshift-kni/oran-o2ims/api/common
 # github.com/openshift-kni/oran-o2ims/api/hardwaremanagement v0.0.0-20250124152543-be560cbe2609 => ./api/hardwaremanagement
 ## explicit; go 1.22.0
 github.com/openshift-kni/oran-o2ims/api/hardwaremanagement/v1alpha1
@@ -1540,6 +1543,7 @@ sigs.k8s.io/structured-merge-diff/v4/value
 sigs.k8s.io/yaml
 sigs.k8s.io/yaml/goyaml.v2
 # github.com/openshift/assisted-service/models => github.com/openshift/assisted-service/models v0.0.0-20230831114549-1922eda29cf8
+# github.com/openshift-kni/oran-o2ims/api/common => ./api/common
 # github.com/openshift-kni/oran-o2ims/api/hardwaremanagement => ./api/hardwaremanagement
 # github.com/openshift-kni/oran-o2ims/api/inventory => ./api/inventory
 # github.com/openshift-kni/oran-o2ims/api/provisioning => ./api/provisioning


Reviews:
user: login: alegacy
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-30T15:07:55Z
user: login: alegacy
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-30T15:09:10Z
user: login: alegacy
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-30T15:10:05Z
user: login: alegacy
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-30T15:11:42Z
user: login: alegacy
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-30T15:14:37Z

Review comments:
diff_hunk: @@ -0,0 +1,120 @@
+/*
+SPDX-FileCopyrightText: Red Hat
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package common
+
+// +genclient
+
+// +kubebuilder:object:generate=true
+// OAuthConfig defines the configurable attributes that represent the authentication mechanism.  This is currently
+// expected to be a way to acquire a token from an OAuth2 server.
+type OAuthConfig struct {
+	// URL represents the base URL of the authorization server. (e.g., https://keycloak.example.com/realms/oran)
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth URL",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	URL string `json:"url"`
+	// TokenEndpoint represents the API endpoint used to acquire a token (e.g., /protocol/openid-connect/token) which
+	// will be appended to the base URL to form the full URL
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Token Endpoint",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	TokenEndpoint string `json:"tokenEndpoint"`
+	// ClientSecretName represents the name of a secret (in the current namespace) which contains the client-id and
+	// client-secret values used by the OAuth client.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Client Secret",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	ClientSecretName string `json:"clientSecretName"`
+	// Scopes represents the OAuth scope values to request when acquiring a token.  Typically, this should be set to
+	// "openid" in addition to any other scopes that the SMO specifically requires (e.g., "roles", "groups", etc...) to
+	// authorize our requests
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Scopes",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	Scopes []string `json:"scopes"`
+	// UsernameClaim represents the claim contained within the OAuth JWT token which holds the username
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Username Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default=preferred_username
+	UsernameClaim string `json:"usernameClaim"`
+	// GroupsClaim represents the claim contained within the OAuth JWT token which holds the list of groups/roles. This
+	// must be a list/array and not a space separated list of names.  It must also be a top level attribute rather than
+	// a nested field in the JSON structure of the JWT object.
+	//    i.e., {"roles": ["a", "b"]} rather than {"realm": {"roles": ["a", "b"}}.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Groups Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default=roles
+	GroupsClaim string `json:"groupsClaim"`
+	// ClientBindingClaim represents the claim contained within the OAuth JWT token which holds the certificate SHA256
+	// fingerprint.  This is expected to be a CEL mapper expression.  It should only be changed in advanced scenarios.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Client Binding Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
path: api/common/common_types.go
user: login: alegacy
body: This is my fault for not structuring this differently in the existing code, but there are some fields in here that are client-only, some that are server-only, and some that are common.  

In the hardware manager case we are always a client so would need everything except the last 3 `*Claim` fields.  

In the other O2 SMO cases we are both a client and a server so need all of the them depending on the actual function, but for reference a server would need everything but `Scopes` and `TokenEndpoint`.

If we were using this internally I'd say no big deal just leave it as is, but since this is going to be exposed in a CRD we should probably clean this up and make a `OAuthClientConfig` for the hardware-manager use cases and keep the other one as is as much as possible (maybe).
created_at: 2025-05-30T15:07:54Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,120 @@
+/*
+SPDX-FileCopyrightText: Red Hat
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package common
+
+// +genclient
+
+// +kubebuilder:object:generate=true
+// OAuthConfig defines the configurable attributes that represent the authentication mechanism.  This is currently
+// expected to be a way to acquire a token from an OAuth2 server.
+type OAuthConfig struct {
+	// URL represents the base URL of the authorization server. (e.g., https://keycloak.example.com/realms/oran)
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth URL",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	URL string `json:"url"`
+	// TokenEndpoint represents the API endpoint used to acquire a token (e.g., /protocol/openid-connect/token) which
+	// will be appended to the base URL to form the full URL
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Token Endpoint",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	TokenEndpoint string `json:"tokenEndpoint"`
+	// ClientSecretName represents the name of a secret (in the current namespace) which contains the client-id and
+	// client-secret values used by the OAuth client.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Client Secret",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	ClientSecretName string `json:"clientSecretName"`
+	// Scopes represents the OAuth scope values to request when acquiring a token.  Typically, this should be set to
+	// "openid" in addition to any other scopes that the SMO specifically requires (e.g., "roles", "groups", etc...) to
+	// authorize our requests
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Scopes",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	Scopes []string `json:"scopes"`
+	// UsernameClaim represents the claim contained within the OAuth JWT token which holds the username
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Username Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default=preferred_username
+	UsernameClaim string `json:"usernameClaim"`
+	// GroupsClaim represents the claim contained within the OAuth JWT token which holds the list of groups/roles. This
+	// must be a list/array and not a space separated list of names.  It must also be a top level attribute rather than
+	// a nested field in the JSON structure of the JWT object.
+	//    i.e., {"roles": ["a", "b"]} rather than {"realm": {"roles": ["a", "b"}}.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Groups Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default=roles
+	GroupsClaim string `json:"groupsClaim"`
+	// ClientBindingClaim represents the claim contained within the OAuth JWT token which holds the certificate SHA256
+	// fingerprint.  This is expected to be a CEL mapper expression.  It should only be changed in advanced scenarios.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Client Binding Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default="has(claims.cnf) ? claims.cnf['x5t#S256'] : []"
+	ClientBindingClaim string `json:"clientBindingClaim"`
+}
+
+// +kubebuilder:object:generate=true
+// TLSConfig defines the TLS specific attributes
+type TLSConfig struct {
+	// SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
path: api/common/common_types.go
user: login: alegacy
body: This doc is likely going to need to be reworded to be a little more generic and a little less ORAN specific.
created_at: 2025-05-30T15:09:10Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,120 @@
+/*
+SPDX-FileCopyrightText: Red Hat
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package common
+
+// +genclient
+
+// +kubebuilder:object:generate=true
+// OAuthConfig defines the configurable attributes that represent the authentication mechanism.  This is currently
+// expected to be a way to acquire a token from an OAuth2 server.
+type OAuthConfig struct {
+	// URL represents the base URL of the authorization server. (e.g., https://keycloak.example.com/realms/oran)
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth URL",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	URL string `json:"url"`
+	// TokenEndpoint represents the API endpoint used to acquire a token (e.g., /protocol/openid-connect/token) which
+	// will be appended to the base URL to form the full URL
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Token Endpoint",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	TokenEndpoint string `json:"tokenEndpoint"`
+	// ClientSecretName represents the name of a secret (in the current namespace) which contains the client-id and
+	// client-secret values used by the OAuth client.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Client Secret",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	ClientSecretName string `json:"clientSecretName"`
+	// Scopes represents the OAuth scope values to request when acquiring a token.  Typically, this should be set to
+	// "openid" in addition to any other scopes that the SMO specifically requires (e.g., "roles", "groups", etc...) to
+	// authorize our requests
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Scopes",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	Scopes []string `json:"scopes"`
+	// UsernameClaim represents the claim contained within the OAuth JWT token which holds the username
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Username Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default=preferred_username
+	UsernameClaim string `json:"usernameClaim"`
+	// GroupsClaim represents the claim contained within the OAuth JWT token which holds the list of groups/roles. This
+	// must be a list/array and not a space separated list of names.  It must also be a top level attribute rather than
+	// a nested field in the JSON structure of the JWT object.
+	//    i.e., {"roles": ["a", "b"]} rather than {"realm": {"roles": ["a", "b"}}.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Groups Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default=roles
+	GroupsClaim string `json:"groupsClaim"`
+	// ClientBindingClaim represents the claim contained within the OAuth JWT token which holds the certificate SHA256
+	// fingerprint.  This is expected to be a CEL mapper expression.  It should only be changed in advanced scenarios.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Client Binding Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default="has(claims.cnf) ? claims.cnf['x5t#S256'] : []"
+	ClientBindingClaim string `json:"clientBindingClaim"`
+}
+
+// +kubebuilder:object:generate=true
+// TLSConfig defines the TLS specific attributes
+type TLSConfig struct {
+	// SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
+	// private key.  The secret is expected to contain a 'tls.key' and 'tls.crt' keys.  If the client is signed by
+	// intermediate CA certificate(s), then it is expected that the full chain is appended to the certificate file with
+	// the device certificate being first and the root CA being last.  It is expected that the certificate CN and DNS SAN configured be equal
+	// to the O2IMS DNS FQDN (e.g., o2ims.apps.<cluster domain name>).  This is to ensure that the certificate can be
+	// used as the ingress certificate as well as the outgoing client certificate.
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="TLS certificate"
+	SecretName *string `json:"secretName"`
+}
+
+// +kubebuilder:object:generate=true
+// AuthType defines the authorization type used for authentication.
+type AuthType string
+
+const (
+	// ServiceAccount represents authentication using a Kubernetes ServiceAccount token. This method leverages
+	// a Kubernetes ServiceAccount to authenticate requests, typically used for internal cluster communication
+	// where the client presents a JWT token issued by the Kubernetes API server.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="ServiceAccount Authentication"
+	ServiceAccount AuthType = "ServiceAccount"
+
+	// Basic represents authentication using HTTP Basic Authentication. This method uses a username and password
+	// combination to authenticate requests, typically encoded in the Authorization header of HTTP requests.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Basic Authentication"
+	Basic AuthType = "Basic"
+
+	// OAuth represents authentication using an OAuth2-based mechanism. This method involves acquiring a token
+	// from an OAuth2 server, which is then used to authenticate requests, typically via a Bearer token in the
+	// Authorization header. Configuration details for OAuth are specified in the OAuthConfig struct.
path: api/common/common_types.go
user: login: alegacy
body: We should continue this doc comment and add that we only support the `client_credentials` grant type.
created_at: 2025-05-30T15:10:04Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,120 @@
+/*
+SPDX-FileCopyrightText: Red Hat
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package common
+
+// +genclient
+
+// +kubebuilder:object:generate=true
+// OAuthConfig defines the configurable attributes that represent the authentication mechanism.  This is currently
+// expected to be a way to acquire a token from an OAuth2 server.
+type OAuthConfig struct {
+	// URL represents the base URL of the authorization server. (e.g., https://keycloak.example.com/realms/oran)
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth URL",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	URL string `json:"url"`
+	// TokenEndpoint represents the API endpoint used to acquire a token (e.g., /protocol/openid-connect/token) which
+	// will be appended to the base URL to form the full URL
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Token Endpoint",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	TokenEndpoint string `json:"tokenEndpoint"`
+	// ClientSecretName represents the name of a secret (in the current namespace) which contains the client-id and
+	// client-secret values used by the OAuth client.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Client Secret",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	ClientSecretName string `json:"clientSecretName"`
+	// Scopes represents the OAuth scope values to request when acquiring a token.  Typically, this should be set to
+	// "openid" in addition to any other scopes that the SMO specifically requires (e.g., "roles", "groups", etc...) to
+	// authorize our requests
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Scopes",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	Scopes []string `json:"scopes"`
+	// UsernameClaim represents the claim contained within the OAuth JWT token which holds the username
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Username Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default=preferred_username
+	UsernameClaim string `json:"usernameClaim"`
+	// GroupsClaim represents the claim contained within the OAuth JWT token which holds the list of groups/roles. This
+	// must be a list/array and not a space separated list of names.  It must also be a top level attribute rather than
+	// a nested field in the JSON structure of the JWT object.
+	//    i.e., {"roles": ["a", "b"]} rather than {"realm": {"roles": ["a", "b"}}.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Groups Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default=roles
+	GroupsClaim string `json:"groupsClaim"`
+	// ClientBindingClaim represents the claim contained within the OAuth JWT token which holds the certificate SHA256
+	// fingerprint.  This is expected to be a CEL mapper expression.  It should only be changed in advanced scenarios.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Client Binding Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default="has(claims.cnf) ? claims.cnf['x5t#S256'] : []"
+	ClientBindingClaim string `json:"clientBindingClaim"`
+}
+
+// +kubebuilder:object:generate=true
+// TLSConfig defines the TLS specific attributes
+type TLSConfig struct {
+	// SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
+	// private key.  The secret is expected to contain a 'tls.key' and 'tls.crt' keys.  If the client is signed by
+	// intermediate CA certificate(s), then it is expected that the full chain is appended to the certificate file with
+	// the device certificate being first and the root CA being last.  It is expected that the certificate CN and DNS SAN configured be equal
+	// to the O2IMS DNS FQDN (e.g., o2ims.apps.<cluster domain name>).  This is to ensure that the certificate can be
+	// used as the ingress certificate as well as the outgoing client certificate.
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="TLS certificate"
+	SecretName *string `json:"secretName"`
+}
+
+// +kubebuilder:object:generate=true
+// AuthType defines the authorization type used for authentication.
+type AuthType string
+
+const (
+	// ServiceAccount represents authentication using a Kubernetes ServiceAccount token. This method leverages
+	// a Kubernetes ServiceAccount to authenticate requests, typically used for internal cluster communication
+	// where the client presents a JWT token issued by the Kubernetes API server.
path: api/common/common_types.go
user: login: alegacy
body: I would be explicit here and state that we assume that the plugin is going to be a service running in this same cluster... rather than in another cluster because then this wouldn't work at all and OAuth2 would need to be used instead... or we'd need to support TLS client certificate authentication to that other cluster's ingress. ... which may not be a bad idea to support, but not today!
created_at: 2025-05-30T15:11:42Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,120 @@
+/*
+SPDX-FileCopyrightText: Red Hat
+
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package common
+
+// +genclient
+
+// +kubebuilder:object:generate=true
+// OAuthConfig defines the configurable attributes that represent the authentication mechanism.  This is currently
+// expected to be a way to acquire a token from an OAuth2 server.
+type OAuthConfig struct {
+	// URL represents the base URL of the authorization server. (e.g., https://keycloak.example.com/realms/oran)
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth URL",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	URL string `json:"url"`
+	// TokenEndpoint represents the API endpoint used to acquire a token (e.g., /protocol/openid-connect/token) which
+	// will be appended to the base URL to form the full URL
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Token Endpoint",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	TokenEndpoint string `json:"tokenEndpoint"`
+	// ClientSecretName represents the name of a secret (in the current namespace) which contains the client-id and
+	// client-secret values used by the OAuth client.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Client Secret",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	ClientSecretName string `json:"clientSecretName"`
+	// Scopes represents the OAuth scope values to request when acquiring a token.  Typically, this should be set to
+	// "openid" in addition to any other scopes that the SMO specifically requires (e.g., "roles", "groups", etc...) to
+	// authorize our requests
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Scopes",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	Scopes []string `json:"scopes"`
+	// UsernameClaim represents the claim contained within the OAuth JWT token which holds the username
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Username Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default=preferred_username
+	UsernameClaim string `json:"usernameClaim"`
+	// GroupsClaim represents the claim contained within the OAuth JWT token which holds the list of groups/roles. This
+	// must be a list/array and not a space separated list of names.  It must also be a top level attribute rather than
+	// a nested field in the JSON structure of the JWT object.
+	//    i.e., {"roles": ["a", "b"]} rather than {"realm": {"roles": ["a", "b"}}.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Groups Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default=roles
+	GroupsClaim string `json:"groupsClaim"`
+	// ClientBindingClaim represents the claim contained within the OAuth JWT token which holds the certificate SHA256
+	// fingerprint.  This is expected to be a CEL mapper expression.  It should only be changed in advanced scenarios.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Client Binding Claim",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	//+kubebuilder:default="has(claims.cnf) ? claims.cnf['x5t#S256'] : []"
+	ClientBindingClaim string `json:"clientBindingClaim"`
+}
+
+// +kubebuilder:object:generate=true
+// TLSConfig defines the TLS specific attributes
+type TLSConfig struct {
+	// SecretName represents the name of a secret (in the current namespace) which contains an X.509 certificate and
+	// private key.  The secret is expected to contain a 'tls.key' and 'tls.crt' keys.  If the client is signed by
+	// intermediate CA certificate(s), then it is expected that the full chain is appended to the certificate file with
+	// the device certificate being first and the root CA being last.  It is expected that the certificate CN and DNS SAN configured be equal
+	// to the O2IMS DNS FQDN (e.g., o2ims.apps.<cluster domain name>).  This is to ensure that the certificate can be
+	// used as the ingress certificate as well as the outgoing client certificate.
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="TLS certificate"
+	SecretName *string `json:"secretName"`
+}
+
+// +kubebuilder:object:generate=true
+// AuthType defines the authorization type used for authentication.
+type AuthType string
+
+const (
+	// ServiceAccount represents authentication using a Kubernetes ServiceAccount token. This method leverages
+	// a Kubernetes ServiceAccount to authenticate requests, typically used for internal cluster communication
+	// where the client presents a JWT token issued by the Kubernetes API server.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="ServiceAccount Authentication"
+	ServiceAccount AuthType = "ServiceAccount"
+
+	// Basic represents authentication using HTTP Basic Authentication. This method uses a username and password
+	// combination to authenticate requests, typically encoded in the Authorization header of HTTP requests.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Basic Authentication"
+	Basic AuthType = "Basic"
+
+	// OAuth represents authentication using an OAuth2-based mechanism. This method involves acquiring a token
+	// from an OAuth2 server, which is then used to authenticate requests, typically via a Bearer token in the
+	// Authorization header. Configuration details for OAuth are specified in the OAuthConfig struct.
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="OAuth Authentication"
+	OAuth AuthType = "OAuth"
+)
+
+// +kubebuilder:object:generate=true
+// AuthConfig defines the configuration for different authentication types.
+// This struct encapsulates the settings required for ServiceAccount, Basic, and OAuth authentication mechanisms.
+type AuthConfig struct {
+	// Type specifies the authentication type to be used (e.g., ServiceAccount, Basic, or OAuth).
+	//+kubebuilder:validation:Enum=ServiceAccount;Basic;OAuth
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Authentication Type",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:select:ServiceAccount","urn:alm:descriptor:com.tectonic.ui:select:Basic","urn:alm:descriptor:com.tectonic.ui:select:OAuth"}
+	Type AuthType `json:"type"`
+
+	// ServiceAccountName specifies the name of the Kubernetes ServiceAccount to use for authentication.
+	// This field is required when Type is set to "ServiceAccount". The ServiceAccount must exist in the
+	// current namespace, and its associated token will be used for authentication.
+	//+optional
+	//+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Service Account Name",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"}
+	ServiceAccountName *string `json:"serviceAccountName,omitempty"`
path: api/common/common_types.go
user: login: alegacy
body: I would leave this out.   The hardware-manager plugin should be instantiated with a service account when the operator creates it (e.g., like we do for the alarm-server, resource-server, etc... they each have there own service account).  
created_at: 2025-05-30T15:14:37Z
author_association: COLLABORATOR

PR comments:
user: login: alegacy
created_at: 2025-05-30T17:45:21Z
body: /lgtm
/approve
author_association: COLLABORATOR
user: login: openshift-ci[bot]
created_at: 2025-05-30T17:45:30Z
body: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/openshift-kni/oran-o2ims/pull/703#issuecomment-2923014383" title="Approved">alegacy</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=openshift-kni%2Foran-o2ims).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/openshift-kni/oran-o2ims/blob/plugin-poc/OWNERS)~~ [alegacy]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
author_association: NONE