@adobe/aio-commerce-lib-auth
Version:
Authentication utilities for Adobe Commerce apps deployed in Adobe App Builder.
295 lines (293 loc) • 14.3 kB
TypeScript
/**
* @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 };