UNPKG

@adobe/aio-commerce-lib-auth

Version:

Authentication utilities for Adobe Commerce apps deployed in Adobe App Builder.

295 lines (293 loc) 14.3 kB
/** * @license * * Copyright 2025 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ import * as valibot21 from "valibot"; import { InferOutput } from "valibot"; //#region source/lib/ims-auth/schema.d.ts /** Validation schema for IMS auth environment values. */ declare const ImsAuthEnvSchema: valibot21.PicklistSchema<["prod", "stage"], undefined>; /** Defines the schema to validate the necessary parameters for the IMS auth service. */ declare const ImsAuthParamsSchema: valibot21.ObjectSchema<{ readonly clientId: valibot21.SchemaWithPipe<readonly [valibot21.StringSchema<`Expected a string value for the IMS auth parameter ${string}`>, valibot21.NonEmptyAction<string, `Expected a non-empty string value for the IMS auth parameter ${string}`>]>; readonly clientSecrets: valibot21.SchemaWithPipe<readonly [valibot21.ArraySchema<valibot21.StringSchema<undefined>, `Expected a string array value for the IMS auth parameter ${string}`>, valibot21.MinLengthAction<string[], number, `Expected at least ${number} items for the IMS auth parameter ${string}`>]>; readonly technicalAccountId: valibot21.SchemaWithPipe<readonly [valibot21.StringSchema<`Expected a string value for the IMS auth parameter ${string}`>, valibot21.NonEmptyAction<string, `Expected a non-empty string value for the IMS auth parameter ${string}`>]>; readonly technicalAccountEmail: valibot21.SchemaWithPipe<readonly [valibot21.StringSchema<"Expected a string value for the IMS auth parameter technicalAccountEmail">, valibot21.EmailAction<string, "Expected a valid email format for technicalAccountEmail">]>; readonly imsOrgId: valibot21.SchemaWithPipe<readonly [valibot21.StringSchema<`Expected a string value for the IMS auth parameter ${string}`>, valibot21.NonEmptyAction<string, `Expected a non-empty string value for the IMS auth parameter ${string}`>]>; readonly environment: valibot21.SchemaWithPipe<readonly [valibot21.OptionalSchema<valibot21.PicklistSchema<["prod", "stage"], undefined>, undefined>]>; readonly context: valibot21.SchemaWithPipe<readonly [valibot21.OptionalSchema<valibot21.StringSchema<undefined>, undefined>]>; readonly scopes: valibot21.SchemaWithPipe<readonly [valibot21.ArraySchema<valibot21.StringSchema<undefined>, `Expected a string array value for the IMS auth parameter ${string}`>, valibot21.MinLengthAction<string[], number, `Expected at least ${number} items for the IMS auth parameter ${string}`>]>; }, undefined>; /** Defines the parameters for the IMS auth service. */ type ImsAuthParams = InferOutput<typeof ImsAuthParamsSchema>; /** Defines the environments accepted by the IMS auth service. */ type ImsAuthEnv = InferOutput<typeof ImsAuthEnvSchema>; //#endregion //#region source/lib/ims-auth/provider.d.ts /** Defines the header keys used for IMS authentication. */ type ImsAuthHeader = "Authorization" | "x-api-key"; /** Defines the headers required for IMS authentication. */ type ImsAuthHeaders = Record<ImsAuthHeader, string>; /** Defines an authentication provider for Adobe IMS. */ type ImsAuthProvider = { getAccessToken: () => Promise<string>; getHeaders: () => Promise<ImsAuthHeaders>; }; /** * Type guard to check if a value is an ImsAuthProvider instance. * * @param provider The value to check. * @returns `true` if the value is an ImsAuthProvider, `false` otherwise. * * @example * ```typescript * import { getImsAuthProvider, isImsAuthProvider } from "@adobe/aio-commerce-lib-auth"; * * // Imagine you have an object that it's not strictly typed as ImsAuthProvider. * const provider = getImsAuthProvider({ ... }) as unknown; * * if (isImsAuthProvider(provider)) { * // TypeScript knows provider is ImsAuthProvider * const token = await provider.getAccessToken(); * } * ``` */ declare function isImsAuthProvider(provider: unknown): provider is ImsAuthProvider; /** * Creates an {@link ImsAuthProvider} based on the provided configuration. * @param authParams An {@link ImsAuthParams} parameter that contains the configuration for the {@link ImsAuthProvider}. * @returns An {@link ImsAuthProvider} instance that can be used to get access token and auth headers. * @example * ```typescript * const config = { * clientId: "your-client-id", * clientSecrets: ["your-client-secret"], * technicalAccountId: "your-technical-account-id", * technicalAccountEmail: "your-account@example.com", * imsOrgId: "your-ims-org-id@AdobeOrg", * scopes: ["AdobeID", "openid"], * environment: "prod", * context: "my-app-context" * }; * * const authProvider = getImsAuthProvider(config); * * // Get access token * const token = await authProvider.getAccessToken(); * console.log(token); // "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..." * * // Get headers for API requests * const headers = await authProvider.getHeaders(); * console.log(headers); * // { * // Authorization: "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...", * // "x-api-key": "your-client-id" * // } * * // Use headers in API calls * const response = await fetch('https://api.adobe.io/some-endpoint', { * headers: await authProvider.getHeaders() * }); * ``` */ declare function getImsAuthProvider(authParams: ImsAuthParams): { getAccessToken: () => Promise<string>; getHeaders: () => Promise<{ Authorization: string; "x-api-key": string; }>; }; //#endregion //#region source/lib/ims-auth/utils.d.ts /** * Asserts the provided configuration for an {@link ImsAuthProvider}. * @param config The configuration to validate. * @throws {CommerceSdkValidationError} If the configuration is invalid. * @example * ```typescript * const config = { * clientId: "your-client-id", * clientSecrets: ["your-client-secret"], * technicalAccountId: "your-technical-account-id", * technicalAccountEmail: "your-account@example.com", * imsOrgId: "your-ims-org-id@AdobeOrg", * scopes: ["AdobeID", "openid"], * environment: "prod", // or "stage" * context: "my-app-context" * }; * * // This will validate the config and throw if invalid * assertImsAuthParams(config); *``` * @example * ```typescript * // Example of a failing assert: * try { * assertImsAuthParams({ * clientId: "valid-client-id", * // Missing required fields like clientSecrets, technicalAccountId, etc. * }); * } catch (error) { * console.error(error.message); // "Invalid ImsAuthProvider configuration" * console.error(error.issues); // Array of validation issues * } * ``` */ declare function assertImsAuthParams(config: Record<PropertyKey, unknown>): asserts config is ImsAuthParams; //#endregion //#region source/lib/integration-auth/schema.d.ts /** * The HTTP methods supported by Commerce. * This is used to determine which headers to include in the signing of the authorization header. */ type HttpMethodInput = "GET" | "POST" | "PUT" | "PATCH" | "DELETE"; /** * The schema for the Commerce Integration parameters. * This is used to validate the parameters passed to the Commerce Integration provider. */ declare const IntegrationAuthParamsSchema: valibot21.NonOptionalSchema<valibot21.ObjectSchema<{ readonly consumerKey: valibot21.SchemaWithPipe<readonly [valibot21.StringSchema<`Expected a string value for the Commerce Integration parameter ${string}`>, valibot21.NonEmptyAction<string, `Expected a non-empty string value for the Commerce Integration parameter ${string}`>]>; readonly consumerSecret: valibot21.SchemaWithPipe<readonly [valibot21.StringSchema<`Expected a string value for the Commerce Integration parameter ${string}`>, valibot21.NonEmptyAction<string, `Expected a non-empty string value for the Commerce Integration parameter ${string}`>]>; readonly accessToken: valibot21.SchemaWithPipe<readonly [valibot21.StringSchema<`Expected a string value for the Commerce Integration parameter ${string}`>, valibot21.NonEmptyAction<string, `Expected a non-empty string value for the Commerce Integration parameter ${string}`>]>; readonly accessTokenSecret: valibot21.SchemaWithPipe<readonly [valibot21.StringSchema<`Expected a string value for the Commerce Integration parameter ${string}`>, valibot21.NonEmptyAction<string, `Expected a non-empty string value for the Commerce Integration parameter ${string}`>]>; }, undefined>, undefined>; /** Defines the parameters required for Commerce Integration authentication. */ type IntegrationAuthParams = InferOutput<typeof IntegrationAuthParamsSchema>; //#endregion //#region source/lib/integration-auth/provider.d.ts /** Defines the header key used for Commerce Integration authentication. */ type IntegrationAuthHeader = "Authorization"; /** Defines the headers required for Commerce Integration authentication. */ type IntegrationAuthHeaders = Record<IntegrationAuthHeader, string>; /** Represents a URL for Adobe Commerce endpoints, accepting either string or URL object. */ type AdobeCommerceUrl = string | URL; /** Defines an authentication provider for Adobe Commerce integrations. */ type IntegrationAuthProvider = { getHeaders: (method: HttpMethodInput, url: AdobeCommerceUrl) => IntegrationAuthHeaders; }; /** * Type guard to check if a value is an IntegrationAuthProvider instance. * * @param provider The value to check. * @returns `true` if the value is an IntegrationAuthProvider, `false` otherwise. * * @example * ```typescript * import { getIntegrationAuthProvider, isIntegrationAuthProvider } from "@adobe/aio-commerce-lib-auth"; * * // Imagine you have an object that it's not strictly typed as IntegrationAuthProvider. * const provider = getIntegrationAuthProvider({ ... }) as unknown; * * if (isIntegrationAuthProvider(provider)) { * // TypeScript knows provider is IntegrationAuthProvider * const headers = provider.getHeaders("GET", "https://api.example.com"); * } * ``` */ declare function isIntegrationAuthProvider(provider: unknown): provider is IntegrationAuthProvider; /** * Creates an {@link IntegrationAuthProvider} based on the provided configuration. * @param authParams The configuration for the integration. * @returns An {@link IntegrationAuthProvider} instance that can be used to get auth headers. * @example * ```typescript * const config = { * consumerKey: "your-consumer-key", * consumerSecret: "your-consumer-secret", * accessToken: "your-access-token", * accessTokenSecret: "your-access-token-secret" * }; * * const authProvider = getIntegrationAuthProvider(config); * * // Get OAuth headers for a REST API call * const headers = authProvider.getHeaders("GET", "https://your-store.com/rest/V1/products"); * console.log(headers); // { Authorization: "OAuth oauth_consumer_key=..., oauth_signature=..." } * * // Can also be used with URL objects * const url = new URL("https://your-store.com/rest/V1/customers"); * const postHeaders = authProvider.getHeaders("POST", url); * ``` */ declare function getIntegrationAuthProvider(authParams: IntegrationAuthParams): IntegrationAuthProvider; //#endregion //#region source/lib/integration-auth/utils.d.ts /** * Asserts the provided configuration for an Adobe Commerce {@link IntegrationAuthProvider}. * @param config The configuration to validate. * @throws {CommerceSdkValidationError} If the configuration is invalid. * @example * ```typescript * const config = { * consumerKey: "your-consumer-key", * consumerSecret: "your-consumer-secret", * accessToken: "your-access-token", * accessTokenSecret: "your-access-token-secret" * }; * * // This will validate the config and throw if invalid * assertIntegrationAuthParams(config); * ``` * @example * ```typescript * // Example of a failing assert: * try { * assertIntegrationAuthParams({ * consumerKey: "valid-consumer-key", * // Missing required fields like consumerSecret, accessToken, accessTokenSecret * }); * } catch (error) { * console.error(error.message); // "Invalid IntegrationAuthProvider configuration" * console.error(error.issues); // Array of validation issues * } * ``` */ declare function assertIntegrationAuthParams(config: Record<PropertyKey, unknown>): asserts config is IntegrationAuthParams; //#endregion //#region source/lib/utils.d.ts /** * Automatically detects and resolves authentication parameters from App Builder action inputs. * Attempts to resolve IMS authentication first, then falls back to Integration authentication. * * @param params The App Builder action inputs containing authentication parameters. * @throws {CommerceSdkValidationError} If the parameters are invalid. * @throws {Error} If neither IMS nor Integration authentication parameters can be resolved. * @example * ```typescript * // Automatic detection (will use IMS if IMS params are present, otherwise Integration) * export function main(params) { * const authProvider = resolveAuthParams(params); * console.log(authProvider.strategy); // "ims" or "integration" * } * ``` */ declare function resolveAuthParams(params: Record<string, unknown>): ({ clientId: string; clientSecrets: string[]; technicalAccountId: string; technicalAccountEmail: string; imsOrgId: string; environment?: "prod" | "stage" | undefined; context?: string | undefined; scopes: string[]; } & { readonly strategy: "ims"; }) | ({ consumerKey: string; consumerSecret: string; accessToken: string; accessTokenSecret: string; } & { readonly strategy: "integration"; }); //#endregion export { type ImsAuthEnv, type ImsAuthParams, type ImsAuthProvider, type IntegrationAuthParams, type IntegrationAuthProvider, assertImsAuthParams, assertIntegrationAuthParams, getImsAuthProvider, getIntegrationAuthProvider, isImsAuthProvider, isIntegrationAuthProvider, resolveAuthParams };