Repository: opensearch-project/OpenSearch-Dashboards (TypeScript)

Issue:
[Proposal] Refactoring data source plugin to support add-on authentication method with plug-in module
# Overview
The purpose of this design document is to outline the approach and specifications for adding an interface in multi data source plugin that allows the seamless integration of authentication method through plugin. This enhancement aims to provide a standardized and user-friendly mechanism for extending the authentication in multi data source plugin.

# User stories
Currently in multi data source, we support these auth types

* No Auth
* Basic Auth
* AWS SigV4 

In AWS SigV4, we only support user based access policies where IAM user comes with IAM access key & secret key that can be used to sign the request.

As a user I want additional support for role based authentication for my OpenSearch domain. Data source plugin already supports AWS SigV4 for authenticating request. I want to add required UI fields and generate access toke, secret key and session token in external plugin and pass them to data source plugin to authenticating request. As a user I want interface in data source plugin to register my own authentication method.

# Requirement
## Functional
* **Modularity**:  Enable OpenSearch-Dashboards to easily accommodate additional authentication methods through external plugins.
* **Standardization**: Establish set of APIs to ensure uniformity and compatibility with existing authentication method.

## Non-functional

* **Scalability**: The system should be able to handle a growing number of authentication methods through plugins without a significant degradation in performance. It should support a scalable architecture that can accommodate an increasing concurrently active plugins.
* **Usability**:  The interface should have a consistent and intuitive design, making it easy for users to manage plugins.
* **Security and Compliance:** Implement security best practices to protect against potential vulnerabilities in plugins. Ensure that the interface and plugins comply with relevant security standards and regulations.

## Architecture Proposal
To meet the outlined requirements, we will introduce a new interface in data source and data source management plugins. These plugins are OpenSearch Dashboards core plugins. This will extend the current multi data source plugin’s capabilities, enabling it to be able to support multiple authentication method.

### Components
* **Server side auth registry** : This map will hold all the details required for signing the request.
* **DataSourcePlugin** : The proposed architecture will add method to DataSourcePluginSetup to register authentication method and to DataSourcePluginStart to retrieve auth registry . This will be in charge of returning OpenSearch client for provided credentials by plugin.
* **Client side auth registry** : This map will hold UI component required for authentication method.
* **DataSourceManagementPlugin**: The proposed architecture will add method to DataSourceManagementPluginSetup to register authentication method with UI elements and to DataSourceManagementPluginStart to retrieve auth registry. This will be in charge of mounting UI component for user input.
* **Plugin**: Plugin should add dataSource and dataSourceManagement as requiredPlugins in plugin’s JSON manifest file named opensearch_dashboards.json. requiredPlugins is an optional list of the other plugins that must be installed and enabled for this plugin to function properly. During setup in both browser-side and server-side plugin, it should register the authentication method to above core plugin.

### Location of Datasource Codebase

The proposed architecture will comprise a set of back-end functionalities sitting within the server [folder](https://github.com/opensearch-project/OpenSearch-Dashboards/tree/main/src/plugins/data_source/server) of the core data_source plugin and a set of front-end functionalities sitting within the public [folder](https://github.com/opensearch-project/OpenSearch-Dashboards/tree/main/src/plugins/data_source_management/public) of the core data_source_management plugin. The interfaces to register authentication method into the registry and get authentication registry will be made accessible via the setup and start hook in plugin.ts. Any core components or plugins that list dataSource and dataSourceManagement as a dependency will have access to these interfaces. During plugin setup stage, it initiates registry to store authentication methods and provide function to register authentication method. When the plugin starts, it returns function to retrieve the authentication registry. During setup stage of both  dataSource 
and  dataSourceManagement  plugins, we need authentication registry to pass to async handler. We are using core. getStartService which allows plugins to get access to APIs available in start inside async handlers. Promise will not resolve until Core and plugin dependencies have completed start. This should only be used inside handlers registered during setup that will only be executed after start lifecycle.

```
# src/plugins/data_source/server/plugin.ts

public async setup(core: CoreSetup<DataSourcePluginStart>) {
    const authRegistryPromise = core.getStartServices().then(([, , selfStart]) => {
      const dataSourcePluginStart = selfStart as DataSourcePluginStart;
      return dataSourcePluginStart.getAuthenticationMethodRegistery();
    });
    .
    .
    .
    const registerCredentialProvider = (method: AuthenticationMethod) => {
      if (this.started) {
        throw new Error('cannot call `registerCredentialProvider` after service startup.');
      }
      this.authMethodsRegistry.registerAuthenticationMethod(method);
    };

    return {
      createDataSourceError: (e: any) => createDataSourceError(e),
      registerCredentialProvider, #This is new API
    };
}

public start(core: CoreStart) {
    this.started = true;
    return {
      getAuthenticationMethodRegistery: () => this.authMethodsRegistry,
    };
  }
```
```
# src/plugins/data_source_management/public/plugin.ts

public setup(core: CoreSetup<DataSourceManagementPluginStart>) {
    const registerAuthenticationMethod = (authMethod: AuthenticationMethod) => {
      if (this.started) {
        throw new Error(
          'cannot call `registerAuthenticationMethod` after data source management startup.'
        );
      }
      this.authMethodsRegistry.registerAuthenticationMethod(authMethod);
    };

    return { registerAuthenticationMethod };
}

public start(core: CoreStart) {
    this.started = true;
    return {
      getAuthenticationMethodRegistery: () => this.authMethodsRegistry,
    };
}
```

#### Interfaces and Classes
**Authentication method registry:**
We will maintain two registry to hold authentication method information. One in server which holds the credential provider and one in public which holds the UI elements to mount on web page.
```
# Registry for server-side

export type IAuthenticationMethodRegistery = Omit<
  AuthenticationMethodRegistery,
  'registerAuthenticationMethod'
>;

export class AuthenticationMethodRegistery {
  private readonly authMethods = new Map<string, AuthenticationMethod>();
  /**
   * Register a authMethods with function to return credentials inside the registry.
   * Authentication Method can only be registered once. subsequent calls with the same method name will throw an error.
   */
  public registerAuthenticationMethod(method: AuthenticationMethod) {
    if (this.authMethods.has(method.name)) {
      throw new Error(`Authentication method '${method.name}' is already registered`);
    }
    this.authMethods.set(method.name, deepFreeze(method) as AuthenticationMethod);
  }

  public getAllAuthenticationMethods() {
    return [...this.authMethods.values()];
  }

  public getAuthenticationMethod(name: string) {
    return this.authMethods.get(name);
  }
}
```

```
# Registry for browser-side

export type IAuthenticationMethodRegistery = Omit<
  AuthenticationMethodRegistery,
  'registerAuthenticationMethod'
>;

export class AuthenticationMethodRegistery {
  private readonly authMethods = new Map<string, AuthenticationMethod>();
  /**
   * Register a authMethods with function to return credentials inside the registry.
   * Authentication Method can only be registered once. subsequent calls with the same method name will throw an error.
   */
  public registerAuthenticationMethod(method: AuthenticationMethod) {
    if (this.authMethods.has(method.name)) {
      throw new Error(`Authentication method '${method.name}' is already registered`);
    }
    this.authMethods.set(method.name, deepFreeze(method) as AuthenticationMethod);
  }

  public getAllAuthenticationMethods() {
    return [...this.authMethods.values()];
  }

  public getAuthenticationMethod(name: string) {
    return this.authMethods.get(name);
  }
}
```

**data_source plugin**
1] **DataSourceCredentialsProvider**: Instance of DataSourceCredentialsProvider will be responsible for providing credentials to sign the request either with Basic auth or AWS SigV4 which are only supported request signing mechanism.
```
export interface DataSourceCredentialsProviderOptions {
  dataSourceAttr: DataSourceAttributes;
  request?: OpenSearchDashboardsRequest;
  cryptography?: CryptographyServiceSetup;
}

export type DataSourceCredentialsProvider = (
  options: DataSourceCredentialsProviderOptions
) => Promise<UsernamePasswordTypedContent | SigV4Content>;
```

2] **DataSourceAttributes**:  Right now we only support [UsernamePasswordTypedContent](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/main/src/plugins/data_source/common/data_sources/types.ts#L31-L34), [SigV4Content](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/main/src/plugins/data_source/common/data_sources/types.ts#L24-L29) and undefined as type for auth credentials. We will need to support more generic type along with existing types to allow credentials in the form of key:value pair. Also we will add new field name: AuthType | string  in   [DataSourceAttributes](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/main/src/plugins/data_source/common/data_sources/types.ts#L8-L17) to identify the authentication method. To ensure compatibility with existing auth methods, we will make default value same as type for Basic and SigV4 authentication method. auth.type in DataSourceAttributes will have only values of AuthType. auth.type will tell data_source plugin, using which method request needs to be signed. Right now we only have two ways: Basic authentication and AWS SigV4 authentication to sign the request.

```
export interface AuthTypeContent {
  [key: string]: string;
}

export interface DataSourceAttributes extends SavedObjectAttributes {
  title: string;
  description?: string;
  endpoint: string;
  auth: {
    type: AuthType;
    credentials: UsernamePasswordTypedContent | SigV4Content | undefined | **AuthTypeContent**;
  };
  lastUpdatedTime?: string;
  **name: AuthType | string;**
}
```
3] **SigV4Content**: This proposed architecture will also extend the ability of multi data source to support authentication using IAM role. Current architecture only supports authenticating as IAM user. As IAM role session requires temporary security credentials through assuming role, we will need additional field for sessionToken in [SigV4Content](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/main/src/plugins/data_source/common/data_sources/types.ts#L24-L29) interface.
```
export interface SigV4Content extends SavedObjectAttributes {
  accessKey: string;
  secretKey: string;
  region: string;
  service?: SigV4ServiceName;
  **sessionToken?: string;** # Newly added field to support temporary security credentials.
}
```
4] **Client**: Based on authentication method type, client will look for authentication method in auth registry to get credentials. Client pooling and caching will be handled by data_source core plugin.
```
# src/plugins/data_source/server/client/configure_client.ts

export const getQueryClient = async (): Promise<Client> => {
   awsCredential = authMethod?.credentialProvider({ dataSourceAttr, request, cryptography });
   type = authMethod?.authType;
   .
   .
   .
   return client; # bases on auth type.
}
```
**data_source_management plugin**
1] **AuthenticationMethod**: To support custom authentication method from plugin, browser side we need option for selection and then form to enter fields which would be credentials or fields which required to retrieve credentials in case role based authentication. Plugins or any component which will be using these API, need to take care of validations as well for those fields. Core data_source_management plugin will be in charge to mount those UI component in parent form and calls sever side API to test connection and save the data source.
```
export interface AuthenticationMethod {
  name: string;
  credentialForm: React.JSX.Element;
  credentialSourceOption: EuiSuperSelectOption<string>;
}

# Map storing UI elements for custom authentication method
authMethods = new Map<string, AuthenticationMethod>();
```

## Tracking issue
https://github.com/opensearch-project/OpenSearch-Dashboards/issues/5838
## Follow up Issue
https://github.com/opensearch-project/OpenSearch-Dashboards/issues/5694



Fix (patch):
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4d4a5efcb1ef..5819b11f7d41 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -42,6 +42,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
 - [Multiple Datasource] Able to Hide "Local Cluster" option from datasource DropDown ([#5827](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5827))
 - [Multiple Datasource] Add api registry and allow it to be added into client config in data source plugin ([#5895](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5895))
 - [Multiple Datasource] Concatenate data source name with index pattern name and change delimiter to double colon ([#5907](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5907))
+- [Multiple Datasource] Refactor client and legacy client to use authentication registry ([#5881](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5881))
 
 ### 🐛 Bug Fixes
 
diff --git a/src/plugins/data_source/common/data_sources/types.ts b/src/plugins/data_source/common/data_sources/types.ts
index d30e5ee710c8..38c14d18ccc4 100644
--- a/src/plugins/data_source/common/data_sources/types.ts
+++ b/src/plugins/data_source/common/data_sources/types.ts
@@ -14,6 +14,7 @@ export interface DataSourceAttributes extends SavedObjectAttributes {
     credentials: UsernamePasswordTypedContent | SigV4Content | undefined | AuthTypeContent;
   };
   lastUpdatedTime?: string;
+  name: AuthType | string;
 }
 
 export interface AuthTypeContent {
@@ -30,6 +31,7 @@ export interface SigV4Content extends SavedObjectAttributes {
   secretKey: string;
   region: string;
   service?: SigV4ServiceName;
+  sessionToken?: string;
 }
 
 export interface UsernamePasswordTypedContent extends SavedObjectAttributes {
diff --git a/src/plugins/data_source/server/auth_registry/authentication_methods_registry.mock.ts b/src/plugins/data_source/server/auth_registry/authentication_methods_registry.mock.ts
new file mode 100644
index 000000000000..41e63798556e
--- /dev/null
+++ b/src/plugins/data_source/server/auth_registry/authentication_methods_registry.mock.ts
@@ -0,0 +1,14 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { IAuthenticationMethodRegistery } from './authentication_methods_registry';
+
+const create = () =>
+  (({
+    getAllAuthenticationMethods: jest.fn(),
+    getAuthenticationMethod: jest.fn(),
+  } as unknown) as jest.Mocked<IAuthenticationMethodRegistery>);
+
+export const authenticationMethodRegisteryMock = { create };
diff --git a/src/plugins/data_source/server/auth_registry/index.ts b/src/plugins/data_source/server/auth_registry/index.ts
index 9352afd8b661..919585a26b96 100644
--- a/src/plugins/data_source/server/auth_registry/index.ts
+++ b/src/plugins/data_source/server/auth_registry/index.ts
@@ -7,3 +7,5 @@ export {
   IAuthenticationMethodRegistery,
   AuthenticationMethodRegistery,
 } from './authentication_methods_registry';
+
+export { authenticationMethodRegisteryMock } from './authentication_methods_registry.mock';
diff --git a/src/plugins/data_source/server/client/configure_client.ts b/src/plugins/data_source/server/client/configure_client.ts
index 984d99565569..4ebee55ab2d6 100644
--- a/src/plugins/data_source/server/client/configure_client.ts
+++ b/src/plugins/data_source/server/client/configure_client.ts
@@ -7,7 +7,7 @@ import { Client, ClientOptions } from '@opensearch-project/opensearch';
 import { Client as LegacyClient } from 'elasticsearch';
 import { Credentials } from 'aws-sdk';
 import { AwsSigv4Signer } from '@opensearch-project/opensearch/aws';
-import { Logger } from '../../../../../src/core/server';
+import { Logger, OpenSearchDashboardsRequest } from '../../../../../src/core/server';
 import {
   AuthType,
   DataSourceAttributes,
@@ -27,6 +27,8 @@ import {
   getDataSource,
   generateCacheKey,
 } from './configure_client_utils';
+import { IAuthenticationMethodRegistery } from '../auth_registry';
+import { authRegistryCredentialProvider } from '../util/credential_provider';
 
 export const configureClient = async (
   {
@@ -35,6 +37,8 @@ export const configureClient = async (
     cryptography,
     testClientDataSourceAttr,
     customApiSchemaRegistryPromise,
+    request,
+    authRegistry,
   }: DataSourceClientParams,
   openSearchClientPoolSetup: OpenSearchClientPoolSetup,
   config: DataSourcePluginConfigType,
@@ -80,6 +84,8 @@ export const configureClient = async (
       cryptography,
       rootClient,
       dataSourceId,
+      request,
+      authRegistry,
       requireDecryption
     );
   } catch (error: any) {
@@ -101,6 +107,8 @@ export const configureClient = async (
  * @param config data source config
  * @param addClientToPool function to add client to client pool
  * @param dataSourceId id of data source saved Object
+ * @param request OpenSearch Dashboards incoming request to read client parameters from header.
+ * @param authRegistry registry to retrieve the credentials provider for the authentication method in order to return the client
  * @param requireDecryption false when creating test client before data source exists
  * @returns Promise of query client
  */
@@ -112,15 +120,31 @@ const getQueryClient = async (
   cryptography?: CryptographyServiceSetup,
   rootClient?: Client,
   dataSourceId?: string,
+  request?: OpenSearchDashboardsRequest,
+  authRegistry?: IAuthenticationMethodRegistery,
   requireDecryption: boolean = true
 ): Promise<Client> => {
-  const {
+  let credential;
+  let {
     auth: { type },
-    endpoint,
+    name,
   } = dataSourceAttr;
+  const { endpoint } = dataSourceAttr;
+  name = name ?? type;
   const clientOptions = parseClientOptions(config, endpoint, registeredSchema);
   const cacheKey = generateCacheKey(dataSourceAttr, dataSourceId);
 
+  const authenticationMethod = authRegistry?.getAuthenticationMethod(name);
+  if (authenticationMethod !== undefined) {
+    const credentialProvider = await authRegistryCredentialProvider(authenticationMethod, {
+      dataSourceAttr,
+      request,
+      cryptography,
+    });
+    credential = credentialProvider.credential;
+    type = credentialProvider.type;
+  }
+
   switch (type) {
     case AuthType.NoAuth:
       if (!rootClient) rootClient = new Client(clientOptions);
@@ -129,9 +153,11 @@ const getQueryClient = async (
       return rootClient.child();
 
     case AuthType.UsernamePasswordType:
-      const credential = requireDecryption
-        ? await getCredential(dataSourceAttr, cryptography!)
-        : (dataSourceAttr.auth.credentials as UsernamePasswordTypedContent);
+      credential =
+        (credential as UsernamePasswordTypedContent) ??
+        (requireDecryption
+          ? await getCredential(dataSourceAttr, cryptography!)
+          : (dataSourceAttr.auth.credentials as UsernamePasswordTypedContent));
 
       if (!rootClient) rootClient = new Client(clientOptions);
       addClientToPool(cacheKey, type, rootClient);
@@ -139,11 +165,13 @@ const getQueryClient = async (
       return getBasicAuthClient(rootClient, credential);
 
     case AuthType.SigV4:
-      const awsCredential = requireDecryption
-        ? await getAWSCredential(dataSourceAttr, cryptography!)
-        : (dataSourceAttr.auth.credentials as SigV4Content);
+      credential =
+        (credential as SigV4Content) ??
+        (requireDecryption
+          ? await getAWSCredential(dataSourceAttr, cryptography!)
+          : (dataSourceAttr.auth.credentials as SigV4Content));
 
-      const awsClient = rootClient ? rootClient : getAWSClient(awsCredential, clientOptions);
+      const awsClient = rootClient ? rootClient : getAWSClient(credential, clientOptions);
       addClientToPool(cacheKey, type, awsClient);
 
       return awsClient;
diff --git a/src/plugins/data_source/server/legacy/configure_legacy_client.ts b/src/plugins/data_source/server/legacy/configure_legacy_client.ts
index 58905b33d85c..8ed1b42cfd2e 100644
--- a/src/plugins/data_source/server/legacy/configure_legacy_client.ts
+++ b/src/plugins/data_source/server/legacy/configure_legacy_client.ts
@@ -14,6 +14,7 @@ import {
   LegacyCallAPIOptions,
   LegacyOpenSearchErrorHelpers,
   Logger,
+  OpenSearchDashboardsRequest,
 } from '../../../../../src/core/server';
 import {
   AuthType,
@@ -34,6 +35,8 @@ import {
   getDataSource,
   generateCacheKey,
 } from '../client/configure_client_utils';
+import { IAuthenticationMethodRegistery } from '../auth_registry';
+import { authRegistryCredentialProvider } from '../util/credential_provider';
 
 export const configureLegacyClient = async (
   {
@@ -41,6 +44,8 @@ export const configureLegacyClient = async (
     savedObjects,
     cryptography,
     customApiSchemaRegistryPromise,
+    request,
+    authRegistry,
   }: DataSourceClientParams,
   callApiParams: LegacyClientCallAPIParams,
   openSearchClientPoolSetup: OpenSearchClientPoolSetup,
@@ -65,7 +70,9 @@ export const configureLegacyClient = async (
       config,
       registeredSchema,
       rootClient,
-      dataSourceId
+      dataSourceId,
+      request,
+      authRegistry
     );
   } catch (error: any) {
     logger.debug(
@@ -96,15 +103,31 @@ const getQueryClient = async (
   config: DataSourcePluginConfigType,
   registeredSchema: any[],
   rootClient?: LegacyClient,
-  dataSourceId?: string
+  dataSourceId?: string,
+  request?: OpenSearchDashboardsRequest,
+  authRegistry?: IAuthenticationMethodRegistery
 ) => {
-  const {
+  let credential;
+  let {
     auth: { type },
-    endpoint: nodeUrl,
+    name,
   } = dataSourceAttr;
+  const { endpoint: nodeUrl } = dataSourceAttr;
+  name = name ?? type;
   const clientOptions = parseClientOptions(config, nodeUrl, registeredSchema);
   const cacheKey = generateCacheKey(dataSourceAttr, dataSourceId);
 
+  const authenticationMethod = authRegistry?.getAuthenticationMethod(name);
+  if (authenticationMethod !== undefined) {
+    const credentialProvider = await authRegistryCredentialProvider(authenticationMethod, {
+      dataSourceAttr,
+      request,
+      cryptography,
+    });
+    credential = credentialProvider.credential;
+    type = credentialProvider.type;
+  }
+
   switch (type) {
     case AuthType.NoAuth:
       if (!rootClient) rootClient = new LegacyClient(clientOptions);
@@ -117,7 +140,9 @@ const getQueryClient = async (
       );
 
     case AuthType.UsernamePasswordType:
-      const credential = await getCredential(dataSourceAttr, cryptography);
+      credential =
+        (credential as UsernamePasswordTypedContent) ??
+        (await getCredential(dataSourceAttr, cryptography));
 
       if (!rootClient) rootClient = new LegacyClient(clientOptions);
       addClientToPool(cacheKey, type, rootClient);
@@ -125,9 +150,10 @@ const getQueryClient = async (
       return getBasicAuthClient(rootClient, { endpoint, clientParams, options }, credential);
 
     case AuthType.SigV4:
-      const awsCredential = await getAWSCredential(dataSourceAttr, cryptography);
+      credential =
+        (credential as SigV4Content) ?? (await getAWSCredential(dataSourceAttr, cryptography));
 
-      const awsClient = rootClient ? rootClient : getAWSClient(awsCredential, clientOptions);
+      const awsClient = rootClient ? rootClient : getAWSClient(credential, clientOptions);
       addClientToPool(cacheKey, type, awsClient);
 
       return await (callAPI.bind(null, awsClient) as LegacyAPICaller)(
diff --git a/src/plugins/data_source/server/plugin.ts b/src/plugins/data_source/server/plugin.ts
index 6bccfbfad662..c75e55809781 100644
--- a/src/plugins/data_source/server/plugin.ts
+++ b/src/plugins/data_source/server/plugin.ts
@@ -168,7 +168,8 @@ export class DataSourcePlugin implements Plugin<DataSourcePluginSetup, DataSourc
     authRegistryPromise: Promise<IAuthenticationMethodRegistery>,
     customApiSchemaRegistryPromise: Promise<CustomApiSchemaRegistry>
   ): IContextProvider<RequestHandler<unknown, unknown, unknown>, 'dataSource'> => {
-    return (context, req) => {
+    return async (context, req) => {
+      const authRegistry = await authRegistryPromise;
       return {
         opensearch: {
           getClient: (dataSourceId: string) => {
@@ -181,6 +182,8 @@ export class DataSourcePlugin implements Plugin<DataSourcePluginSetup, DataSourc
               savedObjects: context.core.savedObjects.client,
               cryptography,
               customApiSchemaRegistryPromise,
+              request: req,
+              authRegistry,
             });
           },
           legacy: {
@@ -190,6 +193,8 @@ export class DataSourcePlugin implements Plugin<DataSourcePluginSetup, DataSourc
                 savedObjects: context.core.savedObjects.client,
                 cryptography,
                 customApiSchemaRegistryPromise,
+                request: req,
+                authRegistry,
               });
             },
           },
diff --git a/src/plugins/data_source/server/types.ts b/src/plugins/data_source/server/types.ts
index 9bd70b142d8b..ede0194ed3ef 100644
--- a/src/plugins/data_source/server/types.ts
+++ b/src/plugins/data_source/server/types.ts
@@ -37,6 +37,10 @@ export interface DataSourceClientParams {
   testClientDataSourceAttr?: DataSourceAttributes;
   // custom API schema registry promise, required for getting registered custom API schema
   customApiSchemaRegistryPromise: Promise<CustomApiSchemaRegistry>;
+  // When client parameters are required to be retrieved from the request header, the caller should provide the request.
+  request?: OpenSearchDashboardsRequest;
+  // To retrieve the credentials provider for the authentication method from the registry in order to return the client.
+  authRegistry?: IAuthenticationMethodRegistery;
 }
 
 export interface DataSourceCredentialsProviderOptions {
diff --git a/src/plugins/data_source/server/util/credential_provider.ts b/src/plugins/data_source/server/util/credential_provider.ts
new file mode 100644
index 000000000000..d737c932fd95
--- /dev/null
+++ b/src/plugins/data_source/server/util/credential_provider.ts
@@ -0,0 +1,14 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { DataSourceCredentialsProviderOptions, AuthenticationMethod } from '../types';
+
+export const authRegistryCredentialProvider = async (
+  authenticationMethod: AuthenticationMethod,
+  options: DataSourceCredentialsProviderOptions
+) => ({
+  credential: await authenticationMethod.credentialProvider(options),
+  type: authenticationMethod.authType,
+});