From 5845a7932c9921c32c49debf66c07ca8b40d82f4 Mon Sep 17 00:00:00 2001 From: Vatsal Parikh Date: Tue, 1 Sep 2026 09:14:26 -0700 Subject: [PATCH 1/2] feat: add AM mediation check to WebAuthn and export storage config types --- .changeset/pink-jars-check.md | 6 ++ e2e/journey-app/components/webauthn-step.ts | 11 +--- interface_mapping.md | 36 ++++++------ .../api-report/journey-client.webauthn.api.md | 2 +- .../src/lib/webauthn/webauthn.mock.data.ts | 33 ++++++++++- .../src/lib/webauthn/webauthn.test.ts | 55 +++++++++++++++++++ .../src/lib/webauthn/webauthn.ts | 30 +++++++--- .../oidc-client/api-report/oidc-client.api.md | 9 +++ .../api-report/oidc-client.types.api.md | 9 +++ .../src/__tests__/types-reexport.typecheck.ts | 6 ++ packages/oidc-client/src/types.ts | 6 +- 11 files changed, 165 insertions(+), 38 deletions(-) create mode 100644 .changeset/pink-jars-check.md diff --git a/.changeset/pink-jars-check.md b/.changeset/pink-jars-check.md new file mode 100644 index 00000000000..a8b19070cb6 --- /dev/null +++ b/.changeset/pink-jars-check.md @@ -0,0 +1,6 @@ +--- +'@forgerock/journey-client': minor +'@forgerock/oidc-client': minor +--- + +Add AM server-side conditional mediation check to `WebAuthn.isConditionalMediationSupported` and export custom storage config types from oidc-client diff --git a/e2e/journey-app/components/webauthn-step.ts b/e2e/journey-app/components/webauthn-step.ts index fe136b202b8..78388b44298 100644 --- a/e2e/journey-app/components/webauthn-step.ts +++ b/e2e/journey-app/components/webauthn-step.ts @@ -65,16 +65,9 @@ export async function handleWebAuthnStep( ) as HTMLInputElement | null; conditionalInput?.focus(); - const isConditionalSupported = await WebAuthn.isConditionalMediationSupported(); + const isConditionalMediation = await WebAuthn.isConditionalMediationSupported(step); - const metadataCallback = WebAuthn.getMetadataCallback(step); - const meta = metadataCallback?.getData<{ - mediation?: CredentialMediationRequirement; - conditional?: boolean; - }>(); - const isConditionalMediation = meta?.mediation === 'conditional' || meta?.conditional === true; - - if (isConditionalSupported && conditionalInput && isConditionalMediation) { + if (isConditionalMediation && conditionalInput) { const controller = new AbortController(); void WebAuthn.authenticate(step, controller.signal) .then(() => submitForm()) diff --git a/interface_mapping.md b/interface_mapping.md index db7be28a768..e6469ef09da 100644 --- a/interface_mapping.md +++ b/interface_mapping.md @@ -859,24 +859,24 @@ const response = await fetch('https://api.example.com/resource', { ## 12. WebAuthn -| Legacy API | New API | Return Type Change | Behavioral Notes | -| ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | ------------------ | -------------------------------------------------------------------------- | -| `import { FRWebAuthn, WebAuthnStepType } from '@forgerock/javascript-sdk'` | `import { WebAuthn, WebAuthnStepType } from '@forgerock/journey-client/webauthn'` | — | Class renamed `FRWebAuthn` → `WebAuthn`. Import path changed to submodule | -| `FRWebAuthn.getWebAuthnStepType(step: FRStep): WebAuthnStepType` | `WebAuthn.getWebAuthnStepType(step: JourneyStep): WebAuthnStepType` | Same | Step type changed to `JourneyStep` | -| `FRWebAuthn.authenticate(step: FRStep, optionsTransformer?): Promise` | `WebAuthn.authenticate(step: JourneyStep): Promise` | `FRStep` → `void` | Mutates step in-place instead of returning it | -| `FRWebAuthn.register(step: FRStep, deviceName?): Promise` | `WebAuthn.register(step: JourneyStep): Promise` | `FRStep` → `void` | Mutates step in-place instead of returning it. Device name not passed here | -| `FRWebAuthn.isWebAuthnSupported(): boolean` | No equivalent exported | — | Check `window.PublicKeyCredential` directly | -| `FRWebAuthn.isConditionalMediationSupported(): Promise` | No equivalent exported | — | Check `PublicKeyCredential.isConditionalMediationAvailable()` directly | -| `FRWebAuthn.getCallbacks(step): WebAuthnCallbacks` | Not exported as public API | — | Internal to `WebAuthn.authenticate/register` | -| `FRWebAuthn.getMetadataCallback(step)` | Not exported as public API | — | Internal | -| `FRWebAuthn.getOutcomeCallback(step)` | Not exported as public API | — | Internal | -| `FRWebAuthn.getTextOutputCallback(step)` | Not exported as public API | — | Internal | -| `FRWebAuthn.getAuthenticationCredential(options)` | Not exported as public API | — | Internal | -| `FRWebAuthn.getAuthenticationOutcome(credential)` | Not exported as public API | — | Internal | -| `FRWebAuthn.getRegistrationCredential(options)` | Not exported as public API | — | Internal | -| `FRWebAuthn.getRegistrationOutcome(credential)` | Not exported as public API | — | Internal | -| `FRWebAuthn.createAuthenticationPublicKey(metadata)` | Not exported as public API | — | Internal | -| `FRWebAuthn.createRegistrationPublicKey(metadata)` | Not exported as public API | — | Internal | +| Legacy API | New API | Return Type Change | Behavioral Notes | +| ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| `import { FRWebAuthn, WebAuthnStepType } from '@forgerock/javascript-sdk'` | `import { WebAuthn, WebAuthnStepType } from '@forgerock/journey-client/webauthn'` | — | Class renamed `FRWebAuthn` → `WebAuthn`. Import path changed to submodule | +| `FRWebAuthn.getWebAuthnStepType(step: FRStep): WebAuthnStepType` | `WebAuthn.getWebAuthnStepType(step: JourneyStep): WebAuthnStepType` | Same | Step type changed to `JourneyStep` | +| `FRWebAuthn.authenticate(step: FRStep, optionsTransformer?): Promise` | `WebAuthn.authenticate(step: JourneyStep): Promise` | `FRStep` → `void` | Mutates step in-place instead of returning it | +| `FRWebAuthn.register(step: FRStep, deviceName?): Promise` | `WebAuthn.register(step: JourneyStep): Promise` | `FRStep` → `void` | Mutates step in-place instead of returning it. Device name not passed here | +| `FRWebAuthn.isWebAuthnSupported(): boolean` | No equivalent exported | — | Check `window.PublicKeyCredential` directly | +| `FRWebAuthn.isConditionalMediationSupported(): Promise` | `WebAuthn.isConditionalMediationSupported(step?): Promise` | Same | Pass a step to also check AM requested conditional mediation (`meta.mediation === 'conditional'`); without a step, only the browser check runs | +| `FRWebAuthn.getCallbacks(step): WebAuthnCallbacks` | Not exported as public API | — | Internal to `WebAuthn.authenticate/register` | +| `FRWebAuthn.getMetadataCallback(step)` | Not exported as public API | — | Internal | +| `FRWebAuthn.getOutcomeCallback(step)` | Not exported as public API | — | Internal | +| `FRWebAuthn.getTextOutputCallback(step)` | Not exported as public API | — | Internal | +| `FRWebAuthn.getAuthenticationCredential(options)` | Not exported as public API | — | Internal | +| `FRWebAuthn.getAuthenticationOutcome(credential)` | Not exported as public API | — | Internal | +| `FRWebAuthn.getRegistrationCredential(options)` | Not exported as public API | — | Internal | +| `FRWebAuthn.getRegistrationOutcome(credential)` | Not exported as public API | — | Internal | +| `FRWebAuthn.createAuthenticationPublicKey(metadata)` | Not exported as public API | — | Internal | +| `FRWebAuthn.createRegistrationPublicKey(metadata)` | Not exported as public API | — | Internal | ### WebAuthn Enums diff --git a/packages/journey-client/api-report/journey-client.webauthn.api.md b/packages/journey-client/api-report/journey-client.webauthn.api.md index 311a1028280..5b995dd7ad3 100644 --- a/packages/journey-client/api-report/journey-client.webauthn.api.md +++ b/packages/journey-client/api-report/journey-client.webauthn.api.md @@ -104,7 +104,7 @@ export abstract class WebAuthn { static getRegistrationOutcome(credential: PublicKeyCredential | null): OutcomeWithName; static getTextOutputCallback(step: JourneyStep): TextOutputCallback | undefined; static getWebAuthnStepType(step: JourneyStep): WebAuthnStepType; - static isConditionalMediationSupported(): Promise; + static isConditionalMediationSupported(step?: JourneyStep): Promise; static register(step: JourneyStep, deviceName?: T): Promise; } diff --git a/packages/journey-client/src/lib/webauthn/webauthn.mock.data.ts b/packages/journey-client/src/lib/webauthn/webauthn.mock.data.ts index dcb4809860d..898176ac442 100644 --- a/packages/journey-client/src/lib/webauthn/webauthn.mock.data.ts +++ b/packages/journey-client/src/lib/webauthn/webauthn.mock.data.ts @@ -3,7 +3,7 @@ * * fr-webauthn.mock.data.ts * - * Copyright (c) 2020 - 2025 Ping Identity Corporation. All rights reserved. + * Copyright (c) 2020 - 2026 Ping Identity Corporation. All rights reserved. * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ @@ -325,6 +325,37 @@ export const webAuthnAuthMetaCallback70StoredUsername = { ], }; +export const webAuthnAuthMetaCallback70Conditional = { + authId: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 ... ', + callbacks: [ + { + type: callbackType.MetadataCallback, + output: [ + { + name: 'data', + value: { + userVerification: 'preferred', + _type: 'WebAuthn', + challenge: 'OHmmFKfBhrUZKkuZJ84lf9N8TaRmQSjRdZyueeSIXAo=', + relyingPartyId: '', + allowCredentials: '', + timeout: '60000', + mediation: 'conditional', + }, + }, + ], + }, + { + type: callbackType.HiddenValueCallback, + output: [ + { name: 'value', value: 'false' }, + { name: 'id', value: 'webAuthnOutcome' }, + ], + input: [{ name: 'IDToken2', value: 'webAuthnOutcome' }], + }, + ], +}; + export const webAuthnAuthMetaCallbackJsonResponse = { authId: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdXRoSW5kZXhWYWx1ZSI6IndlYmF1dGhuIiwib3RrIjoicXN1dTA0anNxZ2hmcGpubjFiM2IxdDh0NTQiLCJhdXRoSW5kZXhUeXBlIjoic2VydmljZSIsInJlYWxtIjoiLyIsInNlc3Npb25JZCI6IipBQUpUU1FBQ01ERUFCSFI1Y0dVQUNFcFhWRjlCVlZSSUFBSlRNUUFBKmV5SjBlWEFpT2lKS1YxUWlMQ0pqZEhraU9pSktWMVFpTENKaGJHY2lPaUpJVXpJMU5pSjkuWlhsS01HVllRV2xQYVVwTFZqRlJhVXhEU214aWJVMXBUMmxLUWsxVVNUUlJNRXBFVEZWb1ZFMXFWVEpKYVhkcFdWZDRia2xxYjJsYVIyeDVTVzR3TGk0M01qbDZSRXhsU0hwM1pXbFVPRll6VDB4cFgycEJMbGxpV1Y5WVl6WTJPVWxJU0MxT01VTk5Va05MZVROdFZFaHliVlJSVDJoV2VVSTBUVUUzYUVoRmFISjFTRU5SVWpWeWVsQnRZVzFpYlRNeFFqQlhSMlZxVEU5allUWllWMEUwTVROSlozRnVXV2gwV0hadlRHaE9VMkpDYUdkUlJFaGFSV1pLVmxaeWNsOTBTRUpJU1Y5elIyMVhNMEZYWm5wTk9WZElXblJMTm10ZmFITm9hemRNUTBkSVkwbzVhVGQ2Wnpob2FUbFROVm8wTVVkbk1rZFpXSFJJTnpoWlRGOVVaVTl5VWtOc1ozTlBkbDlWTWpGRFJ6STBReTFMWVRJNVMxRm9ibFYwTTNCVlozWldiamRCVUhWdWRFdEdaR2h6VERselJ6QlBTVnAwYzNoV1NqTXRPVmc1TmpSM2VrVldSV2w2Vnprek9XNTRlVm94VjNWVVgzWmpTRzFFV2t4eE0yWTJXamswVlVWTU5VNDJjMjVMTWs5U01XeDBOR3BrVld3eWVVMVRaVXR6YzJkb2VIRmlNMnhoZW1WQlVtMDBWM3BUVld4c1JFUTRVVVJuWDNoSFozSktlVmhQZWxCa1RWUnZYeTB0U1c0MFkxVjBTeloxTVdWSVkxOWhZbkZLTlhsRVpWcEpaM04yYkU5eE5qVTJkVU5KV0dzNU9GbElWMHBEWkhSR1MzcGtWV1k1ZG0xNlJIWk9iMmxXTlZnd2RXd3hiRzlTV0dOaFZtTkhVMDlaTlVGNFdITkJkSGd5UVhkVlVXUnViR0pmYTJodWN5MUhXblowZUVOM1lYRldlR2h1T1RsdVVWY3ljWFphUjNCTk1raFVPRzFMYUU5SVIyOVJOQzFWVkZrNVVWbDBNbGcwZGpaZlQzSk5kemxUZEdwSVl6RnRjMTkxVTI1VWVtVmpUR2RYUkVZdFVFNXNVM0J1Ymkxc1EyRlljRXREVmxsS1FVeDVUbWhoWDBJeGQwNTRSRzV0WW5vNVdYVjFXakZMYzFWTkxVZHJjVlJZYkY5c2JqUlBMVEpXVUhoTVFYSjFVblZOZW0xaVgxQndRMjlqY1d4T1Z6Sm1jWHBPV25seVlteE9RVEZXUkdaM04yYzJNMnhmTkhvd05UWkhlRXhOVjBOck5rOTZVQzFMY1RJMVlXTmxSa0ZQWWpGd1JtMXBkVGgzWW5kUGVITmtZa0ZLVW0xSWMxVlJWVzlQWm5aQlpURldORmcyUW5veGNFeG9SV3d0UzNGblkwMDBjMjluYTFab1YyRkhZWFpyVFUxSVFTNVlWRVpOV1d4R2F6bHFSV1V5VG5CamFIZDVZVzVuLmYyS2t1RlhnM05MUU1NbGNnMU1HU2Y2YTZQVmdJalhtUC1wcmJhQTNtTnciLCJleHAiOjE2MTM0OTc0OTksImlhdCI6MTYxMzQ5NzE5OX0.EuDmsY3C6I6vc_x7KlkW4rSQJY1FWevbGGmxkSu4HVU', diff --git a/packages/journey-client/src/lib/webauthn/webauthn.test.ts b/packages/journey-client/src/lib/webauthn/webauthn.test.ts index 60714f14346..fe87b2525ee 100644 --- a/packages/journey-client/src/lib/webauthn/webauthn.test.ts +++ b/packages/journey-client/src/lib/webauthn/webauthn.test.ts @@ -21,9 +21,64 @@ import { webAuthnAuthJSCallback70StoredUsername, webAuthnRegMetaCallback70StoredUsername, webAuthnAuthMetaCallback70StoredUsername, + webAuthnAuthMetaCallback70Conditional, } from './webauthn.mock.data.js'; import { createJourneyStep } from '../step.utils.js'; +describe('Test FRWebAuthn conditional mediation support', () => { + const originalPublicKeyCredential = globalThis.PublicKeyCredential; + + const withConditionalMediationAvailable = (available: boolean) => { + // jsdom has no PublicKeyCredential; install a minimal stub for these tests. + Object.defineProperty(globalThis, 'PublicKeyCredential', { + value: { + isConditionalMediationAvailable: vi.fn().mockResolvedValue(available), + }, + configurable: true, + writable: true, + }); + }; + + afterEach(() => { + Object.defineProperty(globalThis, 'PublicKeyCredential', { + value: originalPublicKeyCredential, + configurable: true, + writable: true, + }); + }); + + it('should return true when the browser supports conditional mediation and no step is given', async () => { + withConditionalMediationAvailable(true); + await expect(WebAuthn.isConditionalMediationSupported()).resolves.toBe(true); + }); + + it('should return false when the browser does not support conditional mediation and no step is given', async () => { + withConditionalMediationAvailable(false); + await expect(WebAuthn.isConditionalMediationSupported()).resolves.toBe(false); + }); + + it('should return false when the browser supports it but AM did not request conditional mediation', async () => { + // eslint-disable-next-line + const step = createJourneyStep(webAuthnAuthMetaCallback70 as any); + withConditionalMediationAvailable(true); + await expect(WebAuthn.isConditionalMediationSupported(step)).resolves.toBe(false); + }); + + it('should return true when the browser supports it and AM requested conditional mediation', async () => { + // eslint-disable-next-line + const step = createJourneyStep(webAuthnAuthMetaCallback70Conditional as any); + withConditionalMediationAvailable(true); + await expect(WebAuthn.isConditionalMediationSupported(step)).resolves.toBe(true); + }); + + it('should return false when AM requested conditional mediation but the browser does not support it', async () => { + // eslint-disable-next-line + const step = createJourneyStep(webAuthnAuthMetaCallback70Conditional as any); + withConditionalMediationAvailable(false); + await expect(WebAuthn.isConditionalMediationSupported(step)).resolves.toBe(false); + }); +}); + describe('Test FRWebAuthn class with 6.5.3 "Passwordless"', () => { it('should return Registration type with register text-output callbacks', () => { // eslint-disable-next-line diff --git a/packages/journey-client/src/lib/webauthn/webauthn.ts b/packages/journey-client/src/lib/webauthn/webauthn.ts index 0c2da99b7f8..74acb8625f2 100644 --- a/packages/journey-client/src/lib/webauthn/webauthn.ts +++ b/packages/journey-client/src/lib/webauthn/webauthn.ts @@ -66,8 +66,9 @@ type WebAuthnMetadata = WebAuthnAuthenticationMetadata | WebAuthnRegistrationMet * Conditional mediation is **server-driven** in this SDK via WebAuthn metadata (`meta.mediation`). * * ```js - * // Optional: feature-detect conditional UI before attempting - * const supportsConditionalUI = await WebAuthn.isConditionalMediationSupported(); + * // Optional: feature-detect conditional UI before attempting. + * // Pass the step to also confirm AM requested conditional mediation. + * const supportsConditionalUI = await WebAuthn.isConditionalMediationSupported(step); * * if (supportsConditionalUI) { * const controller = new AbortController(); @@ -126,14 +127,29 @@ export abstract class WebAuthn { /** * Determines if the browser supports conditional mediation. * - * @return Whether the browser supports conditional mediation + * When a step is provided, this also checks that the AM server requested + * conditional mediation via the WebAuthn metadata (`meta.mediation === 'conditional'`). + * + * @param step Optional step containing the WebAuthn metadata callback + * @return Whether conditional mediation is supported by the browser, + * and requested by AM when a step is provided */ - public static async isConditionalMediationSupported(): Promise { - return ( + public static async isConditionalMediationSupported(step?: JourneyStep): Promise { + const isBrowserSupported = typeof PublicKeyCredential !== 'undefined' && typeof PublicKeyCredential.isConditionalMediationAvailable === 'function' && - (await PublicKeyCredential.isConditionalMediationAvailable()) - ); + (await PublicKeyCredential.isConditionalMediationAvailable()); + + if (!step) { + return isBrowserSupported; + } + + const metadataCallback = this.getMetadataCallback(step); + const meta = metadataCallback?.getOutputValue('data') as + | WebAuthnAuthenticationMetadata + | undefined; + + return isBrowserSupported && meta?.mediation === 'conditional'; } /** diff --git a/packages/oidc-client/api-report/oidc-client.api.md b/packages/oidc-client/api-report/oidc-client.api.md index bcdce96e278..5c0ac2818a3 100644 --- a/packages/oidc-client/api-report/oidc-client.api.md +++ b/packages/oidc-client/api-report/oidc-client.api.md @@ -6,8 +6,11 @@ import { ActionTypes } from '@forgerock/sdk-request-middleware'; import { BaseQueryFn } from '@reduxjs/toolkit/query'; +import { BrowserStorageConfig } from '@forgerock/storage'; import { CombinedState } from '@reduxjs/toolkit/query'; import { CustomLogger } from '@forgerock/sdk-logger'; +import { CustomStorageConfig } from '@forgerock/storage'; +import { CustomStorageObject } from '@forgerock/sdk-types'; import { EnhancedStore } from '@reduxjs/toolkit'; import { FetchArgs } from '@reduxjs/toolkit/query'; import type { FetchBaseQueryError } from '@reduxjs/toolkit/query'; @@ -111,6 +114,8 @@ export interface AuthorizeSuccessResponse { status?: string; } +export { BrowserStorageConfig } + // @public (undocumented) export type BuildAuthorizationData = [string, GetAuthorizationUrlOptions]; @@ -230,6 +235,10 @@ debug: (...args: LogMessage[]) => void; export { CustomLogger } +export { CustomStorageConfig } + +export { CustomStorageObject } + export { GenericError } export { GetAuthorizationUrlOptions } diff --git a/packages/oidc-client/api-report/oidc-client.types.api.md b/packages/oidc-client/api-report/oidc-client.types.api.md index 02a90f352a5..7faf79cf13e 100644 --- a/packages/oidc-client/api-report/oidc-client.types.api.md +++ b/packages/oidc-client/api-report/oidc-client.types.api.md @@ -6,8 +6,11 @@ import { ActionTypes } from '@forgerock/sdk-request-middleware'; import { BaseQueryFn } from '@reduxjs/toolkit/query'; +import { BrowserStorageConfig } from '@forgerock/storage'; import { CombinedState } from '@reduxjs/toolkit/query'; import { CustomLogger } from '@forgerock/sdk-logger'; +import { CustomStorageConfig } from '@forgerock/storage'; +import { CustomStorageObject } from '@forgerock/sdk-types'; import { EnhancedStore } from '@reduxjs/toolkit'; import { FetchArgs } from '@reduxjs/toolkit/query'; import type { FetchBaseQueryError } from '@reduxjs/toolkit/query'; @@ -110,6 +113,8 @@ export interface AuthorizeSuccessResponse { status?: string; } +export { BrowserStorageConfig } + // @public (undocumented) export type BuildAuthorizationData = [string, GetAuthorizationUrlOptions]; @@ -229,6 +234,10 @@ debug: (...args: LogMessage[]) => void; export { CustomLogger } +export { CustomStorageConfig } + +export { CustomStorageObject } + export { GenericError } export { GetAuthorizationUrlOptions } diff --git a/packages/oidc-client/src/__tests__/types-reexport.typecheck.ts b/packages/oidc-client/src/__tests__/types-reexport.typecheck.ts index 7d1d6bdb3dc..9ef1f05b7ad 100644 --- a/packages/oidc-client/src/__tests__/types-reexport.typecheck.ts +++ b/packages/oidc-client/src/__tests__/types-reexport.typecheck.ts @@ -8,6 +8,9 @@ import type { GetAuthorizationUrlOptions, WellknownResponse, StorageConfig, + BrowserStorageConfig, + CustomStorageConfig, + CustomStorageObject, ActionTypes, RequestMiddleware, CustomLogger, @@ -22,6 +25,9 @@ type _Assert = [ GetAuthorizationUrlOptions, WellknownResponse, StorageConfig, + BrowserStorageConfig, + CustomStorageConfig, + CustomStorageObject, ActionTypes, RequestMiddleware, CustomLogger, diff --git a/packages/oidc-client/src/types.ts b/packages/oidc-client/src/types.ts index 6a17dcbfef9..9496a4ae6c4 100644 --- a/packages/oidc-client/src/types.ts +++ b/packages/oidc-client/src/types.ts @@ -1,4 +1,5 @@ -/* Copyright © 2025 - 2026 Ping Identity Corporation. All rights reserved. +/* + * Copyright (c) 2025 - 2026 Ping Identity Corporation. All rights reserved. * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. @@ -18,7 +19,8 @@ export type { } from '@forgerock/sdk-types'; export type { ActionTypes, RequestMiddleware } from '@forgerock/sdk-request-middleware'; export type { CustomLogger, LogLevel } from '@forgerock/sdk-logger'; -export type { StorageConfig } from '@forgerock/storage'; +export type { BrowserStorageConfig, CustomStorageConfig, StorageConfig } from '@forgerock/storage'; +export type { CustomStorageObject } from '@forgerock/sdk-types'; // Re-export functions needed to resolve OidcClient and ClientStore type aliases export { oidc } from './lib/client.store.js'; From b4b6408cd35e37b024bc61748b4d57f37b7b127b Mon Sep 17 00:00:00 2001 From: Vatsal Parikh Date: Mon, 14 Sep 2026 18:37:33 -0700 Subject: [PATCH 2/2] chore(e2e): resolve TODO for the autofill e2e test --- e2e/journey-app/components/text-input.ts | 6 +- .../components/validated-username.ts | 3 +- e2e/journey-app/components/webauthn-step.ts | 42 +- e2e/journey-suites/src/WEBAUTHN_TESTING.md | 38 + .../src/webauthn-device.test.ts | 34 +- .../api-report/device-client.api.md | 2 +- .../api-report/device-client.types.api.md | 2 +- .../api-report/journey-client.api.md | 1014 ++++++++--------- .../api-report/journey-client.types.api.md | 991 ++++++++-------- 9 files changed, 1078 insertions(+), 1054 deletions(-) diff --git a/e2e/journey-app/components/text-input.ts b/e2e/journey-app/components/text-input.ts index 9e46a81483d..7eef0a1af2d 100644 --- a/e2e/journey-app/components/text-input.ts +++ b/e2e/journey-app/components/text-input.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025-2026 Ping Identity Corporation. All rights reserved. + * Copyright (c) 2025 - 2026 Ping Identity Corporation. All rights reserved. * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. @@ -21,10 +21,6 @@ export default function textComponent( input.id = collectorKey; input.name = collectorKey; - if (callback.getType() === 'NameCallback') { - input.setAttribute('autocomplete', 'webauthn'); - } - journeyEl?.appendChild(label); journeyEl?.appendChild(input); diff --git a/e2e/journey-app/components/validated-username.ts b/e2e/journey-app/components/validated-username.ts index fada1fe6901..6bcfa6e02f4 100644 --- a/e2e/journey-app/components/validated-username.ts +++ b/e2e/journey-app/components/validated-username.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2025-2026 Ping Identity Corporation. All rights reserved. + * Copyright (c) 2025 - 2026 Ping Identity Corporation. All rights reserved. * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. @@ -20,7 +20,6 @@ export default function validatedUsernameComponent( input.type = 'text'; input.id = collectorKey; input.name = collectorKey; - input.setAttribute('autocomplete', 'webauthn'); journeyEl?.appendChild(label); journeyEl?.appendChild(input); diff --git a/e2e/journey-app/components/webauthn-step.ts b/e2e/journey-app/components/webauthn-step.ts index 78388b44298..7525f6d378d 100644 --- a/e2e/journey-app/components/webauthn-step.ts +++ b/e2e/journey-app/components/webauthn-step.ts @@ -57,35 +57,39 @@ export async function handleWebAuthnStep( const webAuthnStep = WebAuthn.getWebAuthnStepType(step); if (webAuthnStep === WebAuthnStepType.Authentication) { - // For conditional mediation, we need an input with `autocomplete="webauthn"` to exist. renderCallbacks(journeyEl, callbacks, submitForm); - const conditionalInput = journeyEl.querySelector( - 'input[autocomplete="webauthn"]', - ) as HTMLInputElement | null; - conditionalInput?.focus(); + const hasPasswordInput = journeyEl.querySelector('input[type="password"]') !== null; + const isPasskeyOnly = !hasPasswordInput; + // True only when the browser supports conditional mediation AND AM requested it + // (meta.mediation === 'conditional'). const isConditionalMediation = await WebAuthn.isConditionalMediationSupported(step); - if (isConditionalMediation && conditionalInput) { - const controller = new AbortController(); - void WebAuthn.authenticate(step, controller.signal) - .then(() => submitForm()) - .catch(() => { - setError('WebAuthn failed or was cancelled. Please try again or use a different method.'); - }); + const hasPasskeyAutocompleteValues = callbacks.some((callback) => { + const values = callback.getOutputByName('autocompleteValues', []); + return values.includes('username') && values.includes('webauthn'); + }); + if (isConditionalMediation && hasPasskeyAutocompleteValues) { + journeyEl.querySelectorAll('input[type="text"]').forEach((input) => { + input.setAttribute('autocomplete', 'username webauthn'); + }); + } + // Only auto-invoke WebAuthn when the step offers no normal login path (passkey-only step) + // or when AM requested conditional mediation (silent autofill, no popup). On a hybrid page + // with a password field, WebAuthn must not pop a modal — the user logs in normally. + if (!isPasskeyOnly && !isConditionalMediation) { return { callbacksRendered: true, didSubmit: false }; } - // Fallback to the traditional (prompted) WebAuthn flow. - const webAuthnSuccess = await webauthnComponent(journeyEl, step, 0); - if (webAuthnSuccess) { - submitForm(); - return { callbacksRendered: true, didSubmit: true }; - } + const controller = new AbortController(); + void WebAuthn.authenticate(step, controller.signal) + .then(() => submitForm()) + .catch(() => { + setError('WebAuthn failed or was cancelled. Please try again or use a different method.'); + }); - setError('WebAuthn failed or was cancelled. Please try again or use a different method.'); return { callbacksRendered: true, didSubmit: false }; } diff --git a/e2e/journey-suites/src/WEBAUTHN_TESTING.md b/e2e/journey-suites/src/WEBAUTHN_TESTING.md index 391c0423eb8..456de006504 100644 --- a/e2e/journey-suites/src/WEBAUTHN_TESTING.md +++ b/e2e/journey-suites/src/WEBAUTHN_TESTING.md @@ -71,3 +71,41 @@ The assertion checks that the status message for deleted device contains the sam 2. Credential ids are passed around with query params, which makes it easy to replicate tests without any dependency on external storage. 3. The test provides freedom to choose how to resolve the uuid depending on the app, so the app can decide whether to retrieve the uuid through OIDC, session, or another way. 4. The test lets the app decide how to handle app-specific UI, so this pattern is framework agnostic and can be used by any app that supports Playwright, whether it's React, Vue, or Svelte. + +## Passkey Autofill Journeys + +The `TEST_AutofillPasskeyWebAuthn_*` journeys form a 2x2x2 matrix that tests the presence and absence of three AM-side configuration toggles on the WebAuthn authentication node: + +| Toggle | Journey name part | AM signal | +| --------------------------- | ----------------- | --------------------------------------------------------------------------------------- | +| Passkey autocomplete values | `autocomplete` | Username callback output `autocompleteValues` contains `username` and `webauthn` | +| Conditional mediation | `conditional` | WebAuthn metadata `mediation: 'conditional'` (silent passkey autofill) | +| Authentication button | `button` | WebAuthn node config `conditionalManualButton` (manual "Sign in with a passkey" button) | + +The journey named `TEST_AutofillPasskeyWebAuthn_disabled` is the 000 case: all three toggles off. The other seven combine the toggles, named in the order `autocomplete`, `conditional`, `button` (for example, `TEST_AutofillPasskeyWebAuthn_autocomplete_conditional_button` is the 111 case). + +Each journey's page is a hybrid login page: a username collector, a password collector, and a WebAuthn authentication node on the same step. The journey app follows two rules for these pages: + +1. If the step has a password field (a normal login path), WebAuthn never pops a modal. The user logs in normally; passkeys surface only through the autofill dropdown. +2. WebAuthn is auto-invoked only when AM requested conditional mediation (silent autofill). Passkey-only steps with no password field (like `TEST_WebAuthnAuthentication`) always auto-prompt, since there is no other way to continue. + +| Journey | Autocomplete values | Conditional mediation | Button | Expected app behavior | +| ---------------------------------- | ------------------- | --------------------- | ------- | --------------------------------------------------------------------------------------------------------------- | +| `_disabled` | absent | absent | absent | Plain login form; user logs in with username and password; no WebAuthn prompt | +| `_autocomplete` | present | absent | absent | Plain login form; no decoration because conditional mediation is not active; user logs in normally | +| `_conditional` | absent | present | absent | Silent conditional WebAuthn fires on render; username input is not decorated (no autofill signal from AM) | +| `_conditional_button` | absent | present | present | Same as `_conditional`; the manual button is not rendered by the app (see note below) | +| `_autocomplete_conditional` | present | present | absent | Full passkey autofill: input decorated with `autocomplete="username webauthn"`, silent authentication, no popup | +| `_autocomplete_conditional_button` | present | present | present | Same as `_autocomplete_conditional` (see note below) | +| `_autocomplete_button` | present | absent | present | Plain login form; user logs in normally (see note below) | +| `_button` | absent | absent | present | Plain login form; user logs in normally (see note below) | + +> **Note:** the authentication button feature is not yet supported in the SDK. The `button` toggle is part of the AM journey configuration (node field `conditionalManualButton`), and the journeys exist to cover the matrix, but the journey app (and the SDK) do not render the manual "Sign in with a passkey" button until that feature ships. The `*_button` journeys currently behave like their counterparts without the button part. + +## Journey Prereqs (Passkey Autofill) + +The autofill journeys reuse the same prereqs as the rest of the WebAuthn tests: + +1. Chromium is required, and a CDP virtual authenticator with resident keys, user verification, and automatic presence simulation. +2. Register a passkey first via `TEST_WebAuthn-Registration`, since each authentication journey needs an existing credential. +3. Clear cookies and storage between registration and authentication, since the SDK persists session state in localStorage. diff --git a/e2e/journey-suites/src/webauthn-device.test.ts b/e2e/journey-suites/src/webauthn-device.test.ts index b79c2518b04..ea59dfe2bea 100644 --- a/e2e/journey-suites/src/webauthn-device.test.ts +++ b/e2e/journey-suites/src/webauthn-device.test.ts @@ -136,9 +136,7 @@ test.describe('WebAuthn conditional autofill (passkey)', () => { await cdp.send('WebAuthn.disable'); }); - // TODO: This test is currently skipped because the journey used does not allow enabling conditional mediation in admin console - // When we start using v2.0 of Page Node in admin console, this test can be executed again - test.skip('registers a passkey then authenticates via conditional autofill', async ({ page }) => { + test('registers a passkey then authenticates via conditional autofill', async ({ page }) => { const { clickButton, navigate } = asyncEvents(page); await test.step('Register a WebAuthn credential', async () => { @@ -161,24 +159,26 @@ test.describe('WebAuthn conditional autofill (passkey)', () => { }); await test.step('Authenticate using conditional UI / passkey autofill', async () => { - // Ensure we are not reusing an existing AM session. - // This makes the test exercise passkey auth, not cookie auth. + // Ensure we are not reusing an existing AM session. Cookies alone aren't enough: + // the SDK persists session state in localStorage, so clear that too, or the app + // renders the stale "Complete" screen instead of starting a new journey. await page.context().clearCookies(); + await page.evaluate(() => { + localStorage.clear(); + sessionStorage.clear(); + }); // This journey emits conditional mediation metadata and should complete via background // WebAuthn (journey-app triggers the request and submits when a credential is returned). - await navigate('/?clientId=tenant&journey=TEST_AutofillPasskeyWebAuthn'); - - const conditionalInput = page.locator('input[autocomplete="webauthn"]'); - await expect(conditionalInput).toBeVisible({ timeout: 10000 }); - await conditionalInput.focus(); - await expect(conditionalInput).toBeFocused(); - - // Re-enable presence simulation so the in-flight WebAuthn request can resolve. - await cdp.send('WebAuthn.setAutomaticPresenceSimulation', { - authenticatorId, - enabled: true, - }); + // + // We don't assert the intermediate "pending" autocomplete=webauthn input here: with + // automaticPresenceSimulation on, Chrome's virtual authenticator resolves a conditional + // get() almost immediately (no native picker UI to wait on like a real authenticator), + // so the app reaches "Complete" faster than a post-navigation assertion can reliably + // observe that input. We assert the completed outcome instead. + await navigate( + '/?clientId=tenant&journey=TEST_AutofillPasskeyWebAuthn_autocomplete_conditional', + ); // With a virtual authenticator configured for automatic presence simulation, this should // complete without any manual click. diff --git a/packages/device-client/api-report/device-client.api.md b/packages/device-client/api-report/device-client.api.md index 1f509bc2cbb..797330f24de 100644 --- a/packages/device-client/api-report/device-client.api.md +++ b/packages/device-client/api-report/device-client.api.md @@ -112,7 +112,7 @@ export type Device = { export type DeviceClient = ReturnType; // @public -export const deviceClient: (config: ConfigOptions) => { +export const deviceClient: (config: LegacyConfigOptions) => { oath: { get: (query: RetrieveOathQuery) => Promise; // @public -export const deviceClient: (config: ConfigOptions) => { +export const deviceClient: (config: LegacyConfigOptions) => { oath: { get: (query: RetrieveOathQuery) => Promise Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -import { ActionTypes } from '@forgerock/sdk-request-middleware'; -import { AuthResponse } from '@forgerock/sdk-types'; -import { Callback } from '@forgerock/sdk-types'; -import { CallbackType } from '@forgerock/sdk-types'; -import { callbackType } from '@forgerock/sdk-types'; -import { createWellknownError } from '@forgerock/sdk-utilities'; -import { CustomLogger } from '@forgerock/sdk-logger'; -import { FailedPolicyRequirement } from '@forgerock/sdk-types'; -import { FailureDetail } from '@forgerock/sdk-types'; -import { GenericError } from '@forgerock/sdk-types'; -import { isValidWellknownUrl } from '@forgerock/sdk-utilities'; -import { JourneyClientConfig } from '@forgerock/sdk-types'; -import { JourneyServerConfig } from '@forgerock/sdk-types'; -import { LegacyServerConfig } from '@forgerock/sdk-types'; -import { LogLevel } from '@forgerock/sdk-logger'; -import { makeJourneyConfig } from '@forgerock/sdk-utilities'; -import { NameValue } from '@forgerock/sdk-types'; -import { PolicyKey } from '@forgerock/sdk-types'; -import { PolicyParams } from '@forgerock/sdk-types'; -import { PolicyRequirement } from '@forgerock/sdk-types'; -import { RequestMiddleware } from '@forgerock/sdk-request-middleware'; -import { Step } from '@forgerock/sdk-types'; -import { StepDetail } from '@forgerock/sdk-types'; -import { StepType } from '@forgerock/sdk-types'; -import { WellknownResponse } from '@forgerock/sdk-types'; - -export { ActionTypes }; - -// @public -export class AttributeInputCallback extends BaseCallback { - constructor(payload: Callback); - getFailedPolicies(): PolicyRequirement[]; - getName(): string; - getPolicies(): Record; - getPrompt(): string; - isRequired(): boolean; - // (undocumented) - payload: Callback; - setValidateOnly(value: boolean): void; - setValue(value: T): void; -} - -export { AuthResponse }; - -// @public -export class BaseCallback { - constructor(payload: Callback); - getInputValue(selector?: number | string): unknown; - getOutputByName(name: string, defaultValue: T): T; - getOutputValue(selector?: number | string): unknown; - getType(): CallbackType; - // (undocumented) - payload: Callback; - setInputValue(value: unknown, selector?: number | string | RegExp): void; -} - -export { Callback }; - -// @public (undocumented) -export type CallbackFactory = (callback: Callback) => BaseCallback; - -export { CallbackType }; - -export { callbackType }; - -// @public -export class ChoiceCallback extends BaseCallback { - constructor(payload: Callback); - getChoices(): string[]; - getDefaultChoice(): number; - getPrompt(): string; - // (undocumented) - payload: Callback; - setChoiceIndex(index: number): void; - setChoiceValue(value: string): void; -} - -// @public -export class ConfirmationCallback extends BaseCallback { - constructor(payload: Callback); - getDefaultOption(): number; - getMessageType(): number; - getOptions(): string[]; - getOptionType(): number; - getPrompt(): string; - // (undocumented) - payload: Callback; - setOptionIndex(index: number): void; - setOptionValue(value: string): void; -} - -// @public (undocumented) -export function createCallback(callback: Callback): BaseCallback; - -// @public (undocumented) -export function createJourneyStep(payload: Step, callbackFactory?: CallbackFactory): JourneyStep; - -export { createWellknownError }; - -export { CustomLogger }; - -// @public -export class DeviceProfileCallback extends BaseCallback { - constructor(payload: Callback); - getMessage(): string; - isLocationRequired(): boolean; - isMetadataRequired(): boolean; - // (undocumented) - payload: Callback; - setProfile(profile: DeviceProfileData): void; -} - -// @public (undocumented) -export interface DeviceProfileData { - // (undocumented) - identifier: string; - // (undocumented) - location?: Geolocation_2 | Record; - // (undocumented) - metadata?: { - hardware: { - display: { - [key: string]: string | number | null; - }; - [key: string]: any; - }; - browser: { - [key: string]: string | number | null; - }; - platform: { - [key: string]: string | number | null; - }; - }; -} - -export { FailedPolicyRequirement }; - -export { FailureDetail }; - -export { GenericError }; - -// @public (undocumented) -interface Geolocation_2 { - // (undocumented) - latitude: number; - // (undocumented) - longitude: number; -} -export { Geolocation_2 as Geolocation }; - -// @public -export class HiddenValueCallback extends BaseCallback { - constructor(payload: Callback); - // (undocumented) - payload: Callback; -} - -// @public (undocumented) -export interface IdPValue { - // (undocumented) - provider: string; - // (undocumented) - uiConfig: { - [key: string]: string; - }; -} - -// @internal -export interface InternalJourneyClientConfig { - // (undocumented) - error?: GenericError; - // (undocumented) - serverConfig: ResolvedServerConfig; -} - -export { isValidWellknownUrl }; - -// @public -export function journey(input: { - config: JourneyClientConfig; - requestMiddleware?: RequestMiddleware[]; - logger?: { - level: LogLevel; - custom?: CustomLogger; - }; -}): Promise; - -// @public -export interface JourneyClient { - // (undocumented) - next: (step: JourneyStep, options?: NextOptions) => Promise; - // (undocumented) - redirect: (step: JourneyStep) => Promise; - // (undocumented) - resume: (url: string, options?: ResumeOptions) => Promise; - // (undocumented) - start: (options?: StartParam) => Promise; - // (undocumented) - subscribe: (listener: () => void) => () => void; - // (undocumented) - terminate: (options?: { query?: Record }) => Promise; -} - -export { JourneyClientConfig }; - -// @public (undocumented) -export type JourneyLoginFailure = AuthResponse & { - type: StepType.LoginFailure; - payload: Step; - getCode: () => number; - getDetail: () => FailureDetail | undefined; - getMessage: () => string | undefined; - getProcessedMessage: (messageCreator?: MessageCreator) => ProcessedPropertyError[]; - getReason: () => string | undefined; -}; - -// @public (undocumented) -export type JourneyLoginSuccess = AuthResponse & { - type: StepType.LoginSuccess; - payload: Step; - getRealm: () => string | undefined; - getSessionToken: () => string | undefined; - getSuccessUrl: () => string | undefined; -}; - -// @public (undocumented) -export type JourneyResult = JourneyStep | JourneyLoginSuccess | JourneyLoginFailure | GenericError; - -export { JourneyServerConfig }; - -// @public (undocumented) -export type JourneyStep = AuthResponse & { - type: StepType.Step; - payload: Step; - callbacks: BaseCallback[]; - getCallbackOfType: (type: CallbackType) => T; - getCallbacksOfType: (type: CallbackType) => T[]; - setCallbackValue: (type: CallbackType, value: unknown) => void; - getDescription: () => string | undefined; - getHeader: () => string | undefined; - getStage: () => string | undefined; -}; - -// @public -export class KbaCreateCallback extends BaseCallback { - constructor(payload: Callback); - getPredefinedQuestions(): string[]; - getPrompt(): string; - isAllowedUserDefinedQuestions(): boolean; - // (undocumented) - payload: Callback; - setAnswer(answer: string): void; - setQuestion(question: string): void; -} - -export { LegacyServerConfig }; - -export { LogLevel }; - -// @public (undocumented) -export interface MessageCreator { - // (undocumented) - [key: string]: ( - propertyName: string, - params?: { - [key: string]: unknown; - }, - ) => string; -} - -// @public -export class MetadataCallback extends BaseCallback { - constructor(payload: Callback); - getData(): T; - // (undocumented) - payload: Callback; -} - -// @public -export class NameCallback extends BaseCallback { - constructor(payload: Callback); - getPrompt(): string; - // (undocumented) - payload: Callback; - setName(name: string): void; -} - -export { NameValue }; - -// @public (undocumented) -export interface NextOptions { - // (undocumented) - query?: Record; -} - -// @public -export class PasswordCallback extends BaseCallback { - constructor(payload: Callback); - getFailedPolicies(): PolicyRequirement[]; - getPolicies(): string[]; - getPrompt(): string; - // (undocumented) - payload: Callback; - setPassword(password: string): void; -} - -// @public -export class PingOneProtectEvaluationCallback extends BaseCallback { - constructor(payload: Callback); - getPauseBehavioralData(): boolean; - // (undocumented) - payload: Callback; - setClientError(errorMessage: string): void; - setData(data: string): void; -} - -// @public -export class PingOneProtectInitializeCallback extends BaseCallback { - constructor(payload: Callback); - getConfig(): - | Record - | { - envId: string; - consoleLogEnabled: boolean; - deviceAttributesToIgnore: string[]; - customHost: string; - lazyMetadata: boolean; - behavioralDataCollection: boolean; - deviceKeyRsyncIntervals: number; - enableTrust: boolean; - disableTags: boolean; - disableHub: boolean; - }; - // (undocumented) - payload: Callback; - // (undocumented) - setClientError(errorMessage: string): void; -} - -export { PolicyKey }; - -export { PolicyParams }; - -export { PolicyRequirement }; - -// @public -export class PollingWaitCallback extends BaseCallback { - constructor(payload: Callback); - getMessage(): string; - getWaitTime(): number; - // (undocumented) - payload: Callback; -} - -// @public (undocumented) -export interface ProcessedPropertyError { - // (undocumented) - detail: FailedPolicyRequirement; - // (undocumented) - messages: string[]; -} - -// @public -export class ReCaptchaCallback extends BaseCallback { - constructor(payload: Callback); - getSiteKey(): string; - // (undocumented) - payload: Callback; - setResult(result: string): void; -} - -// @public -export class ReCaptchaEnterpriseCallback extends BaseCallback { - constructor(payload: Callback); - getApiUrl(): string; - getElementClass(): string; - getSiteKey(): string; - // (undocumented) - payload: Callback; - setAction(action: string): void; - setClientError(error: string): void; - setPayload(payload: unknown): void; - setResult(result: string): void; -} - -// @public -export class RedirectCallback extends BaseCallback { - constructor(payload: Callback); - getRedirectUrl(): string; - // (undocumented) - payload: Callback; -} - -export { RequestMiddleware }; - -// @public -export interface ResolvedServerConfig { - // (undocumented) - baseUrl: string; - // (undocumented) - paths: { - authenticate: string; - sessions: string; - }; -} - -// @public (undocumented) -export interface ResumeOptions { - // (undocumented) - journey?: string; - // (undocumented) - query?: Record; -} - -// @public -export class SelectIdPCallback extends BaseCallback { - constructor(payload: Callback); - getProviders(): IdPValue[]; - // (undocumented) - payload: Callback; - setProvider(value: string): void; -} - -// @public (undocumented) -export interface StartParam { - // (undocumented) - journey: string; - // (undocumented) - query?: Record; -} - -export { Step }; - -export { StepDetail }; - -export { StepType }; - -// @public -export class SuspendedTextOutputCallback extends TextOutputCallback { - constructor(payload: Callback); - // (undocumented) - payload: Callback; -} - -// @public -export class TermsAndConditionsCallback extends BaseCallback { - constructor(payload: Callback); - getCreateDate(): Date | null; - getTerms(): string; - getVersion(): string; - // (undocumented) - payload: Callback; - setAccepted(accepted?: boolean): void; -} - -// @public -export class TextInputCallback extends BaseCallback { - constructor(payload: Callback); - getPrompt(): string; - // (undocumented) - payload: Callback; - setInput(input: string): void; -} - -// @public -export class TextOutputCallback extends BaseCallback { - constructor(payload: Callback); - getMessage(): string; - getMessageType(): string; - // (undocumented) - payload: Callback; -} - -// @public -export class ValidatedCreatePasswordCallback extends BaseCallback { - constructor(payload: Callback); - getFailedPolicies(): PolicyRequirement[]; - getPolicies(): Record; - getPrompt(): string; - isRequired(): boolean; - // (undocumented) - payload: Callback; - setPassword(password: string): void; - setValidateOnly(value: boolean): void; -} - -// @public -export class ValidatedCreateUsernameCallback extends BaseCallback { - constructor(payload: Callback); - getFailedPolicies(): PolicyRequirement[]; - getPolicies(): Record; - getPrompt(): string; - isRequired(): boolean; - // (undocumented) - payload: Callback; - setName(name: string): void; - setValidateOnly(value: boolean): void; -} - -export { WellknownResponse }; - -// (No @packageDocumentation comment for this package) -``` +## API Report File for "@forgerock/journey-client" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { ActionTypes } from '@forgerock/sdk-request-middleware'; +import { AuthResponse } from '@forgerock/sdk-types'; +import { Callback } from '@forgerock/sdk-types'; +import { CallbackType } from '@forgerock/sdk-types'; +import { callbackType } from '@forgerock/sdk-types'; +import { createWellknownError } from '@forgerock/sdk-utilities'; +import { CustomLogger } from '@forgerock/sdk-logger'; +import { FailedPolicyRequirement } from '@forgerock/sdk-types'; +import { FailureDetail } from '@forgerock/sdk-types'; +import { GenericError } from '@forgerock/sdk-types'; +import { isValidWellknownUrl } from '@forgerock/sdk-utilities'; +import { JourneyClientConfig } from '@forgerock/sdk-types'; +import { JourneyServerConfig } from '@forgerock/sdk-types'; +import { LegacyServerConfig } from '@forgerock/sdk-types'; +import { LogLevel } from '@forgerock/sdk-logger'; +import { makeJourneyConfig } from '@forgerock/sdk-utilities'; +import { NameValue } from '@forgerock/sdk-types'; +import { PolicyKey } from '@forgerock/sdk-types'; +import { PolicyParams } from '@forgerock/sdk-types'; +import { PolicyRequirement } from '@forgerock/sdk-types'; +import { RequestMiddleware } from '@forgerock/sdk-request-middleware'; +import { Step } from '@forgerock/sdk-types'; +import { StepDetail } from '@forgerock/sdk-types'; +import { StepType } from '@forgerock/sdk-types'; +import { WellknownResponse } from '@forgerock/sdk-types'; + +export { ActionTypes } + +// @public +export class AttributeInputCallback extends BaseCallback { + constructor(payload: Callback); + getFailedPolicies(): PolicyRequirement[]; + getName(): string; + getPolicies(): Record; + getPrompt(): string; + isRequired(): boolean; + // (undocumented) + payload: Callback; + setValidateOnly(value: boolean): void; + setValue(value: T): void; +} + +export { AuthResponse } + +// @public +export class BaseCallback { + constructor(payload: Callback); + getInputValue(selector?: number | string): unknown; + getOutputByName(name: string, defaultValue: T): T; + getOutputValue(selector?: number | string): unknown; + getType(): CallbackType; + // (undocumented) + payload: Callback; + setInputValue(value: unknown, selector?: number | string | RegExp): void; +} + +export { Callback } + +// @public (undocumented) +export type CallbackFactory = (callback: Callback) => BaseCallback; + +export { CallbackType } + +export { callbackType } + +// @public +export class ChoiceCallback extends BaseCallback { + constructor(payload: Callback); + getChoices(): string[]; + getDefaultChoice(): number; + getPrompt(): string; + // (undocumented) + payload: Callback; + setChoiceIndex(index: number): void; + setChoiceValue(value: string): void; +} + +// @public +export class ConfirmationCallback extends BaseCallback { + constructor(payload: Callback); + getDefaultOption(): number; + getMessageType(): number; + getOptions(): string[]; + getOptionType(): number; + getPrompt(): string; + // (undocumented) + payload: Callback; + setOptionIndex(index: number): void; + setOptionValue(value: string): void; +} + +// @public (undocumented) +export function createCallback(callback: Callback): BaseCallback; + +export { createWellknownError } + +export { CustomLogger } + +// @public +export class DeviceProfileCallback extends BaseCallback { + constructor(payload: Callback); + getMessage(): string; + isLocationRequired(): boolean; + isMetadataRequired(): boolean; + // (undocumented) + payload: Callback; + setProfile(profile: DeviceProfileData): void; +} + +// @public (undocumented) +export interface DeviceProfileData { + // (undocumented) + identifier: string; + // (undocumented) + location?: Geolocation_2 | Record; + // (undocumented) + metadata?: { + hardware: { + display: { + [key: string]: string | number | null; + }; + [key: string]: any; + }; + browser: { + [key: string]: string | number | null; + }; + platform: { + [key: string]: string | number | null; + }; + }; +} + +export { FailedPolicyRequirement } + +export { FailureDetail } + +export { GenericError } + +// @public (undocumented) +interface Geolocation_2 { + // (undocumented) + latitude: number; + // (undocumented) + longitude: number; +} +export { Geolocation_2 as Geolocation } + +// @public +export class HiddenValueCallback extends BaseCallback { + constructor(payload: Callback); + // (undocumented) + payload: Callback; +} + +// @public (undocumented) +export interface IdPValue { + // (undocumented) + provider: string; + // (undocumented) + uiConfig: { + [key: string]: string; + }; +} + +// @internal +export interface InternalJourneyClientConfig { + // (undocumented) + error?: GenericError; + // (undocumented) + serverConfig: ResolvedServerConfig; +} + +export { isValidWellknownUrl } + +// @public +export function journey(input: { + config: JourneyClientConfig; + requestMiddleware?: RequestMiddleware[]; + logger?: { + level: LogLevel; + custom?: CustomLogger; + }; +}): Promise; + +// @public +export interface JourneyClient { + // (undocumented) + next: (step: JourneyStep, options?: NextOptions) => Promise; + // (undocumented) + redirect: (step: JourneyStep) => Promise; + // (undocumented) + resume: (url: string, options?: ResumeOptions) => Promise; + // (undocumented) + start: (options?: StartParam) => Promise; + // (undocumented) + subscribe: (listener: () => void) => () => void; + // (undocumented) + terminate: (options?: { + query?: Record; + }) => Promise; +} + +export { JourneyClientConfig } + +// @public (undocumented) +export type JourneyLoginFailure = AuthResponse & { + type: StepType.LoginFailure; + payload: Step; + getCode: () => number; + getDetail: () => FailureDetail | undefined; + getMessage: () => string | undefined; + getProcessedMessage: (messageCreator?: MessageCreator) => ProcessedPropertyError[]; + getReason: () => string | undefined; +}; + +// @public (undocumented) +export type JourneyLoginSuccess = AuthResponse & { + type: StepType.LoginSuccess; + payload: Step; + getRealm: () => string | undefined; + getSessionToken: () => string | undefined; + getSuccessUrl: () => string | undefined; +}; + +// @public (undocumented) +export type JourneyResult = JourneyStep | JourneyLoginSuccess | JourneyLoginFailure | GenericError; + +export { JourneyServerConfig } + +// @public (undocumented) +export type JourneyStep = AuthResponse & { + type: StepType.Step; + payload: Step; + callbacks: BaseCallback[]; + getCallbackOfType: (type: CallbackType) => T; + getCallbacksOfType: (type: CallbackType) => T[]; + setCallbackValue: (type: CallbackType, value: unknown) => void; + getDescription: () => string | undefined; + getHeader: () => string | undefined; + getStage: () => string | undefined; +}; + +// @public +export class KbaCreateCallback extends BaseCallback { + constructor(payload: Callback); + getPredefinedQuestions(): string[]; + getPrompt(): string; + isAllowedUserDefinedQuestions(): boolean; + // (undocumented) + payload: Callback; + setAnswer(answer: string): void; + setQuestion(question: string): void; +} + +export { LegacyServerConfig } + +export { LogLevel } + +export { makeJourneyConfig } + +// @public (undocumented) +export interface MessageCreator { + // (undocumented) + [key: string]: (propertyName: string, params?: { + [key: string]: unknown; + }) => string; +} + +// @public +export class MetadataCallback extends BaseCallback { + constructor(payload: Callback); + getData(): T; + // (undocumented) + payload: Callback; +} + +// @public +export class NameCallback extends BaseCallback { + constructor(payload: Callback); + getPrompt(): string; + // (undocumented) + payload: Callback; + setName(name: string): void; +} + +export { NameValue } + +// @public (undocumented) +export interface NextOptions { + // (undocumented) + query?: Record; +} + +// @public +export class PasswordCallback extends BaseCallback { + constructor(payload: Callback); + getFailedPolicies(): PolicyRequirement[]; + getPolicies(): string[]; + getPrompt(): string; + // (undocumented) + payload: Callback; + setPassword(password: string): void; +} + +// @public +export class PingOneProtectEvaluationCallback extends BaseCallback { + constructor(payload: Callback); + getPauseBehavioralData(): boolean; + // (undocumented) + payload: Callback; + setClientError(errorMessage: string): void; + setData(data: string): void; +} + +// @public +export class PingOneProtectInitializeCallback extends BaseCallback { + constructor(payload: Callback); + getConfig(): Record | { + envId: string; + consoleLogEnabled: boolean; + deviceAttributesToIgnore: string[]; + customHost: string; + lazyMetadata: boolean; + behavioralDataCollection: boolean; + deviceKeyRsyncIntervals: number; + enableTrust: boolean; + disableTags: boolean; + disableHub: boolean; + }; + // (undocumented) + payload: Callback; + // (undocumented) + setClientError(errorMessage: string): void; +} + +export { PolicyKey } + +export { PolicyParams } + +export { PolicyRequirement } + +// @public +export class PollingWaitCallback extends BaseCallback { + constructor(payload: Callback); + getMessage(): string; + getWaitTime(): number; + // (undocumented) + payload: Callback; +} + +// @public (undocumented) +export interface ProcessedPropertyError { + // (undocumented) + detail: FailedPolicyRequirement; + // (undocumented) + messages: string[]; +} + +// @public +export class ReCaptchaCallback extends BaseCallback { + constructor(payload: Callback); + getSiteKey(): string; + // (undocumented) + payload: Callback; + setResult(result: string): void; +} + +// @public +export class ReCaptchaEnterpriseCallback extends BaseCallback { + constructor(payload: Callback); + getApiUrl(): string; + getElementClass(): string; + getSiteKey(): string; + // (undocumented) + payload: Callback; + setAction(action: string): void; + setClientError(error: string): void; + setPayload(payload: unknown): void; + setResult(result: string): void; +} + +// @public +export class RedirectCallback extends BaseCallback { + constructor(payload: Callback); + getRedirectUrl(): string; + // (undocumented) + payload: Callback; +} + +export { RequestMiddleware } + +// @public +export interface ResolvedServerConfig { + // (undocumented) + baseUrl: string; + // (undocumented) + paths: { + authenticate: string; + sessions: string; + }; +} + +// @public (undocumented) +export interface ResumeOptions { + // (undocumented) + journey?: string; + // (undocumented) + query?: Record; +} + +// @public +export class SelectIdPCallback extends BaseCallback { + constructor(payload: Callback); + getProviders(): IdPValue[]; + // (undocumented) + payload: Callback; + setProvider(value: string): void; +} + +// @public (undocumented) +export interface StartParam { + // (undocumented) + journey: string; + // (undocumented) + query?: Record; +} + +export { Step } + +export { StepDetail } + +export { StepType } + +// @public +export class SuspendedTextOutputCallback extends TextOutputCallback { + constructor(payload: Callback); + // (undocumented) + payload: Callback; +} + +// @public +export class TermsAndConditionsCallback extends BaseCallback { + constructor(payload: Callback); + getCreateDate(): Date | null; + getTerms(): string; + getVersion(): string; + // (undocumented) + payload: Callback; + setAccepted(accepted?: boolean): void; +} + +// @public +export class TextInputCallback extends BaseCallback { + constructor(payload: Callback); + getPrompt(): string; + // (undocumented) + payload: Callback; + setInput(input: string): void; +} + +// @public +export class TextOutputCallback extends BaseCallback { + constructor(payload: Callback); + getMessage(): string; + getMessageType(): string; + // (undocumented) + payload: Callback; +} + +// @public +export class ValidatedCreatePasswordCallback extends BaseCallback { + constructor(payload: Callback); + getFailedPolicies(): PolicyRequirement[]; + getPolicies(): Record; + getPrompt(): string; + isRequired(): boolean; + // (undocumented) + payload: Callback; + setPassword(password: string): void; + setValidateOnly(value: boolean): void; +} + +// @public +export class ValidatedCreateUsernameCallback extends BaseCallback { + constructor(payload: Callback); + getFailedPolicies(): PolicyRequirement[]; + getPolicies(): Record; + getPrompt(): string; + isRequired(): boolean; + // (undocumented) + payload: Callback; + setName(name: string): void; + setValidateOnly(value: boolean): void; +} + +export { WellknownResponse } + +// (No @packageDocumentation comment for this package) + +``` diff --git a/packages/journey-client/api-report/journey-client.types.api.md b/packages/journey-client/api-report/journey-client.types.api.md index 59ff118690a..7dcb8224e56 100644 --- a/packages/journey-client/api-report/journey-client.types.api.md +++ b/packages/journey-client/api-report/journey-client.types.api.md @@ -1,501 +1,490 @@ -## API Report File for "@forgerock/journey-client" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -import { ActionTypes } from '@forgerock/sdk-request-middleware'; -import { AuthResponse } from '@forgerock/sdk-types'; -import { Callback } from '@forgerock/sdk-types'; -import { CallbackType } from '@forgerock/sdk-types'; -import { createWellknownError } from '@forgerock/sdk-utilities'; -import { CustomLogger } from '@forgerock/sdk-logger'; -import { FailedPolicyRequirement } from '@forgerock/sdk-types'; -import { FailureDetail } from '@forgerock/sdk-types'; -import { GenericError } from '@forgerock/sdk-types'; -import { isValidWellknownUrl } from '@forgerock/sdk-utilities'; -import { JourneyClientConfig } from '@forgerock/sdk-types'; -import { JourneyServerConfig } from '@forgerock/sdk-types'; -import { LegacyServerConfig } from '@forgerock/sdk-types'; -import { LogLevel } from '@forgerock/sdk-logger'; -import { NameValue } from '@forgerock/sdk-types'; -import { PolicyKey } from '@forgerock/sdk-types'; -import { PolicyParams } from '@forgerock/sdk-types'; -import { PolicyRequirement } from '@forgerock/sdk-types'; -import { RequestMiddleware } from '@forgerock/sdk-request-middleware'; -import { Step } from '@forgerock/sdk-types'; -import { StepDetail } from '@forgerock/sdk-types'; -import { StepType } from '@forgerock/sdk-types'; -import { WellknownResponse } from '@forgerock/sdk-types'; - -export { ActionTypes }; - -// @public -export class AttributeInputCallback extends BaseCallback { - constructor(payload: Callback); - getFailedPolicies(): PolicyRequirement[]; - getName(): string; - getPolicies(): Record; - getPrompt(): string; - isRequired(): boolean; - // (undocumented) - payload: Callback; - setValidateOnly(value: boolean): void; - setValue(value: T): void; -} - -export { AuthResponse }; - -// @public -export class BaseCallback { - constructor(payload: Callback); - getInputValue(selector?: number | string): unknown; - getOutputByName(name: string, defaultValue: T): T; - getOutputValue(selector?: number | string): unknown; - getType(): CallbackType; - // (undocumented) - payload: Callback; - setInputValue(value: unknown, selector?: number | string | RegExp): void; -} - -export { Callback }; - -// @public (undocumented) -export type CallbackFactory = (callback: Callback) => BaseCallback; - -export { CallbackType }; - -// @public -export class ChoiceCallback extends BaseCallback { - constructor(payload: Callback); - getChoices(): string[]; - getDefaultChoice(): number; - getPrompt(): string; - // (undocumented) - payload: Callback; - setChoiceIndex(index: number): void; - setChoiceValue(value: string): void; -} - -// @public -export class ConfirmationCallback extends BaseCallback { - constructor(payload: Callback); - getDefaultOption(): number; - getMessageType(): number; - getOptions(): string[]; - getOptionType(): number; - getPrompt(): string; - // (undocumented) - payload: Callback; - setOptionIndex(index: number): void; - setOptionValue(value: string): void; -} - -// @public (undocumented) -export function createCallback(callback: Callback): BaseCallback; - -export { createWellknownError }; - -export { CustomLogger }; - -// @public -export class DeviceProfileCallback extends BaseCallback { - constructor(payload: Callback); - getMessage(): string; - isLocationRequired(): boolean; - isMetadataRequired(): boolean; - // (undocumented) - payload: Callback; - setProfile(profile: DeviceProfileData): void; -} - -// @public (undocumented) -export interface DeviceProfileData { - // (undocumented) - identifier: string; - // (undocumented) - location?: Geolocation_2 | Record; - // (undocumented) - metadata?: { - hardware: { - display: { - [key: string]: string | number | null; - }; - [key: string]: any; - }; - browser: { - [key: string]: string | number | null; - }; - platform: { - [key: string]: string | number | null; - }; - }; -} - -export { FailedPolicyRequirement }; - -export { FailureDetail }; - -export { GenericError }; - -// @public (undocumented) -interface Geolocation_2 { - // (undocumented) - latitude: number; - // (undocumented) - longitude: number; -} -export { Geolocation_2 as Geolocation }; - -// @public -export class HiddenValueCallback extends BaseCallback { - constructor(payload: Callback); - // (undocumented) - payload: Callback; -} - -// @public (undocumented) -export interface IdPValue { - // (undocumented) - provider: string; - // (undocumented) - uiConfig: { - [key: string]: string; - }; -} - -// @internal -export interface InternalJourneyClientConfig { - // (undocumented) - error?: GenericError; - // (undocumented) - serverConfig: ResolvedServerConfig; -} - -export { isValidWellknownUrl }; - -// @public -export function journey(input: { - config: JourneyClientConfig; - requestMiddleware?: RequestMiddleware[]; - logger?: { - level: LogLevel; - custom?: CustomLogger; - }; -}): Promise; - -// @public -export interface JourneyClient { - // (undocumented) - next: (step: JourneyStep, options?: NextOptions) => Promise; - // (undocumented) - redirect: (step: JourneyStep) => Promise; - // (undocumented) - resume: (url: string, options?: ResumeOptions) => Promise; - // (undocumented) - start: (options?: StartParam) => Promise; - // (undocumented) - subscribe: (listener: () => void) => () => void; - // (undocumented) - terminate: (options?: { query?: Record }) => Promise; -} - -export { JourneyClientConfig }; - -// @public (undocumented) -export type JourneyLoginFailure = AuthResponse & { - type: StepType.LoginFailure; - payload: Step; - getCode: () => number; - getDetail: () => FailureDetail | undefined; - getMessage: () => string | undefined; - getProcessedMessage: (messageCreator?: MessageCreator) => ProcessedPropertyError[]; - getReason: () => string | undefined; -}; - -// @public (undocumented) -export type JourneyLoginSuccess = AuthResponse & { - type: StepType.LoginSuccess; - payload: Step; - getRealm: () => string | undefined; - getSessionToken: () => string | undefined; - getSuccessUrl: () => string | undefined; -}; - -// @public (undocumented) -export type JourneyResult = JourneyStep | JourneyLoginSuccess | JourneyLoginFailure | GenericError; - -export { JourneyServerConfig }; - -// @public (undocumented) -export type JourneyStep = AuthResponse & { - type: StepType.Step; - payload: Step; - callbacks: BaseCallback[]; - getCallbackOfType: (type: CallbackType) => T; - getCallbacksOfType: (type: CallbackType) => T[]; - setCallbackValue: (type: CallbackType, value: unknown) => void; - getDescription: () => string | undefined; - getHeader: () => string | undefined; - getStage: () => string | undefined; -}; - -// @public -export class KbaCreateCallback extends BaseCallback { - constructor(payload: Callback); - getPredefinedQuestions(): string[]; - getPrompt(): string; - isAllowedUserDefinedQuestions(): boolean; - // (undocumented) - payload: Callback; - setAnswer(answer: string): void; - setQuestion(question: string): void; -} - -export { LegacyServerConfig }; - -export { LogLevel }; - -// @public (undocumented) -export interface MessageCreator { - // (undocumented) - [key: string]: ( - propertyName: string, - params?: { - [key: string]: unknown; - }, - ) => string; -} - -// @public -export class MetadataCallback extends BaseCallback { - constructor(payload: Callback); - getData(): T; - // (undocumented) - payload: Callback; -} - -// @public -export class NameCallback extends BaseCallback { - constructor(payload: Callback); - getPrompt(): string; - // (undocumented) - payload: Callback; - setName(name: string): void; -} - -export { NameValue }; - -// @public (undocumented) -export interface NextOptions { - // (undocumented) - query?: Record; -} - -// @public -export class PasswordCallback extends BaseCallback { - constructor(payload: Callback); - getFailedPolicies(): PolicyRequirement[]; - getPolicies(): string[]; - getPrompt(): string; - // (undocumented) - payload: Callback; - setPassword(password: string): void; -} - -// @public -export class PingOneProtectEvaluationCallback extends BaseCallback { - constructor(payload: Callback); - getPauseBehavioralData(): boolean; - // (undocumented) - payload: Callback; - setClientError(errorMessage: string): void; - setData(data: string): void; -} - -// @public -export class PingOneProtectInitializeCallback extends BaseCallback { - constructor(payload: Callback); - getConfig(): - | Record - | { - envId: string; - consoleLogEnabled: boolean; - deviceAttributesToIgnore: string[]; - customHost: string; - lazyMetadata: boolean; - behavioralDataCollection: boolean; - deviceKeyRsyncIntervals: number; - enableTrust: boolean; - disableTags: boolean; - disableHub: boolean; - }; - // (undocumented) - payload: Callback; - // (undocumented) - setClientError(errorMessage: string): void; -} - -export { PolicyKey }; - -export { PolicyParams }; - -export { PolicyRequirement }; - -// @public -export class PollingWaitCallback extends BaseCallback { - constructor(payload: Callback); - getMessage(): string; - getWaitTime(): number; - // (undocumented) - payload: Callback; -} - -// @public (undocumented) -export interface ProcessedPropertyError { - // (undocumented) - detail: FailedPolicyRequirement; - // (undocumented) - messages: string[]; -} - -// @public -export class ReCaptchaCallback extends BaseCallback { - constructor(payload: Callback); - getSiteKey(): string; - // (undocumented) - payload: Callback; - setResult(result: string): void; -} - -// @public -export class ReCaptchaEnterpriseCallback extends BaseCallback { - constructor(payload: Callback); - getApiUrl(): string; - getElementClass(): string; - getSiteKey(): string; - // (undocumented) - payload: Callback; - setAction(action: string): void; - setClientError(error: string): void; - setPayload(payload: unknown): void; - setResult(result: string): void; -} - -// @public -export class RedirectCallback extends BaseCallback { - constructor(payload: Callback); - getRedirectUrl(): string; - // (undocumented) - payload: Callback; -} - -export { RequestMiddleware }; - -// @public -export interface ResolvedServerConfig { - // (undocumented) - baseUrl: string; - // (undocumented) - paths: { - authenticate: string; - sessions: string; - }; -} - -// @public (undocumented) -export interface ResumeOptions { - // (undocumented) - journey?: string; - // (undocumented) - query?: Record; -} - -// @public -export class SelectIdPCallback extends BaseCallback { - constructor(payload: Callback); - getProviders(): IdPValue[]; - // (undocumented) - payload: Callback; - setProvider(value: string): void; -} - -// @public (undocumented) -export interface StartParam { - // (undocumented) - journey: string; - // (undocumented) - query?: Record; -} - -export { Step }; - -export { StepDetail }; - -export { StepType }; - -// @public -export class SuspendedTextOutputCallback extends TextOutputCallback { - constructor(payload: Callback); - // (undocumented) - payload: Callback; -} - -// @public -export class TermsAndConditionsCallback extends BaseCallback { - constructor(payload: Callback); - getCreateDate(): Date | null; - getTerms(): string; - getVersion(): string; - // (undocumented) - payload: Callback; - setAccepted(accepted?: boolean): void; -} - -// @public -export class TextInputCallback extends BaseCallback { - constructor(payload: Callback); - getPrompt(): string; - // (undocumented) - payload: Callback; - setInput(input: string): void; -} - -// @public -export class TextOutputCallback extends BaseCallback { - constructor(payload: Callback); - getMessage(): string; - getMessageType(): string; - // (undocumented) - payload: Callback; -} - -// @public -export class ValidatedCreatePasswordCallback extends BaseCallback { - constructor(payload: Callback); - getFailedPolicies(): PolicyRequirement[]; - getPolicies(): Record; - getPrompt(): string; - isRequired(): boolean; - // (undocumented) - payload: Callback; - setPassword(password: string): void; - setValidateOnly(value: boolean): void; -} - -// @public -export class ValidatedCreateUsernameCallback extends BaseCallback { - constructor(payload: Callback); - getFailedPolicies(): PolicyRequirement[]; - getPolicies(): Record; - getPrompt(): string; - isRequired(): boolean; - // (undocumented) - payload: Callback; - setName(name: string): void; - setValidateOnly(value: boolean): void; -} - -export { WellknownResponse }; - -// (No @packageDocumentation comment for this package) -``` +## API Report File for "@forgerock/journey-client" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { ActionTypes } from '@forgerock/sdk-request-middleware'; +import { AuthResponse } from '@forgerock/sdk-types'; +import { Callback } from '@forgerock/sdk-types'; +import { CallbackType } from '@forgerock/sdk-types'; +import { createWellknownError } from '@forgerock/sdk-utilities'; +import { CustomLogger } from '@forgerock/sdk-logger'; +import { FailedPolicyRequirement } from '@forgerock/sdk-types'; +import { FailureDetail } from '@forgerock/sdk-types'; +import { GenericError } from '@forgerock/sdk-types'; +import { isValidWellknownUrl } from '@forgerock/sdk-utilities'; +import { JourneyClientConfig } from '@forgerock/sdk-types'; +import { JourneyServerConfig } from '@forgerock/sdk-types'; +import { LegacyServerConfig } from '@forgerock/sdk-types'; +import { LogLevel } from '@forgerock/sdk-logger'; +import { NameValue } from '@forgerock/sdk-types'; +import { PolicyKey } from '@forgerock/sdk-types'; +import { PolicyParams } from '@forgerock/sdk-types'; +import { PolicyRequirement } from '@forgerock/sdk-types'; +import { RequestMiddleware } from '@forgerock/sdk-request-middleware'; +import { Step } from '@forgerock/sdk-types'; +import { StepDetail } from '@forgerock/sdk-types'; +import { StepType } from '@forgerock/sdk-types'; +import { WellknownResponse } from '@forgerock/sdk-types'; + +export { ActionTypes } + +// @public +export class AttributeInputCallback extends BaseCallback { + constructor(payload: Callback); + getFailedPolicies(): PolicyRequirement[]; + getName(): string; + getPolicies(): Record; + getPrompt(): string; + isRequired(): boolean; + // (undocumented) + payload: Callback; + setValidateOnly(value: boolean): void; + setValue(value: T): void; +} + +export { AuthResponse } + +// @public +export class BaseCallback { + constructor(payload: Callback); + getInputValue(selector?: number | string): unknown; + getOutputByName(name: string, defaultValue: T): T; + getOutputValue(selector?: number | string): unknown; + getType(): CallbackType; + // (undocumented) + payload: Callback; + setInputValue(value: unknown, selector?: number | string | RegExp): void; +} + +export { Callback } + +// @public (undocumented) +export type CallbackFactory = (callback: Callback) => BaseCallback; + +export { CallbackType } + +// @public +export class ChoiceCallback extends BaseCallback { + constructor(payload: Callback); + getChoices(): string[]; + getDefaultChoice(): number; + getPrompt(): string; + // (undocumented) + payload: Callback; + setChoiceIndex(index: number): void; + setChoiceValue(value: string): void; +} + +// @public +export class ConfirmationCallback extends BaseCallback { + constructor(payload: Callback); + getDefaultOption(): number; + getMessageType(): number; + getOptions(): string[]; + getOptionType(): number; + getPrompt(): string; + // (undocumented) + payload: Callback; + setOptionIndex(index: number): void; + setOptionValue(value: string): void; +} + +// @public (undocumented) +export function createCallback(callback: Callback): BaseCallback; + +export { createWellknownError } + +export { CustomLogger } + +// @public +export class DeviceProfileCallback extends BaseCallback { + constructor(payload: Callback); + getMessage(): string; + isLocationRequired(): boolean; + isMetadataRequired(): boolean; + // (undocumented) + payload: Callback; + setProfile(profile: DeviceProfileData): void; +} + +// @public (undocumented) +export interface DeviceProfileData { + // (undocumented) + identifier: string; + // (undocumented) + location?: Geolocation_2 | Record; + // (undocumented) + metadata?: { + hardware: { + display: { + [key: string]: string | number | null; + }; + [key: string]: any; + }; + browser: { + [key: string]: string | number | null; + }; + platform: { + [key: string]: string | number | null; + }; + }; +} + +export { FailedPolicyRequirement } + +export { FailureDetail } + +export { GenericError } + +// @public (undocumented) +interface Geolocation_2 { + // (undocumented) + latitude: number; + // (undocumented) + longitude: number; +} +export { Geolocation_2 as Geolocation } + +// @public +export class HiddenValueCallback extends BaseCallback { + constructor(payload: Callback); + // (undocumented) + payload: Callback; +} + +// @public (undocumented) +export interface IdPValue { + // (undocumented) + provider: string; + // (undocumented) + uiConfig: { + [key: string]: string; + }; +} + +// @internal +export interface InternalJourneyClientConfig { + // (undocumented) + error?: GenericError; + // (undocumented) + serverConfig: ResolvedServerConfig; +} + +export { isValidWellknownUrl } + +// @public +export interface JourneyClient { + // (undocumented) + next: (step: JourneyStep, options?: NextOptions) => Promise; + // (undocumented) + redirect: (step: JourneyStep) => Promise; + // (undocumented) + resume: (url: string, options?: ResumeOptions) => Promise; + // (undocumented) + start: (options?: StartParam) => Promise; + // (undocumented) + subscribe: (listener: () => void) => () => void; + // (undocumented) + terminate: (options?: { + query?: Record; + }) => Promise; +} + +export { JourneyClientConfig } + +// @public (undocumented) +export type JourneyLoginFailure = AuthResponse & { + type: StepType.LoginFailure; + payload: Step; + getCode: () => number; + getDetail: () => FailureDetail | undefined; + getMessage: () => string | undefined; + getProcessedMessage: (messageCreator?: MessageCreator) => ProcessedPropertyError[]; + getReason: () => string | undefined; +}; + +// @public (undocumented) +export type JourneyLoginSuccess = AuthResponse & { + type: StepType.LoginSuccess; + payload: Step; + getRealm: () => string | undefined; + getSessionToken: () => string | undefined; + getSuccessUrl: () => string | undefined; +}; + +// @public (undocumented) +export type JourneyResult = JourneyStep | JourneyLoginSuccess | JourneyLoginFailure | GenericError; + +export { JourneyServerConfig } + +// @public (undocumented) +export type JourneyStep = AuthResponse & { + type: StepType.Step; + payload: Step; + callbacks: BaseCallback[]; + getCallbackOfType: (type: CallbackType) => T; + getCallbacksOfType: (type: CallbackType) => T[]; + setCallbackValue: (type: CallbackType, value: unknown) => void; + getDescription: () => string | undefined; + getHeader: () => string | undefined; + getStage: () => string | undefined; +}; + +// @public +export class KbaCreateCallback extends BaseCallback { + constructor(payload: Callback); + getPredefinedQuestions(): string[]; + getPrompt(): string; + isAllowedUserDefinedQuestions(): boolean; + // (undocumented) + payload: Callback; + setAnswer(answer: string): void; + setQuestion(question: string): void; +} + +export { LegacyServerConfig } + +export { LogLevel } + +// @public (undocumented) +export interface MessageCreator { + // (undocumented) + [key: string]: (propertyName: string, params?: { + [key: string]: unknown; + }) => string; +} + +// @public +export class MetadataCallback extends BaseCallback { + constructor(payload: Callback); + getData(): T; + // (undocumented) + payload: Callback; +} + +// @public +export class NameCallback extends BaseCallback { + constructor(payload: Callback); + getPrompt(): string; + // (undocumented) + payload: Callback; + setName(name: string): void; +} + +export { NameValue } + +// @public (undocumented) +export interface NextOptions { + // (undocumented) + query?: Record; +} + +// @public +export class PasswordCallback extends BaseCallback { + constructor(payload: Callback); + getFailedPolicies(): PolicyRequirement[]; + getPolicies(): string[]; + getPrompt(): string; + // (undocumented) + payload: Callback; + setPassword(password: string): void; +} + +// @public +export class PingOneProtectEvaluationCallback extends BaseCallback { + constructor(payload: Callback); + getPauseBehavioralData(): boolean; + // (undocumented) + payload: Callback; + setClientError(errorMessage: string): void; + setData(data: string): void; +} + +// @public +export class PingOneProtectInitializeCallback extends BaseCallback { + constructor(payload: Callback); + getConfig(): Record | { + envId: string; + consoleLogEnabled: boolean; + deviceAttributesToIgnore: string[]; + customHost: string; + lazyMetadata: boolean; + behavioralDataCollection: boolean; + deviceKeyRsyncIntervals: number; + enableTrust: boolean; + disableTags: boolean; + disableHub: boolean; + }; + // (undocumented) + payload: Callback; + // (undocumented) + setClientError(errorMessage: string): void; +} + +export { PolicyKey } + +export { PolicyParams } + +export { PolicyRequirement } + +// @public +export class PollingWaitCallback extends BaseCallback { + constructor(payload: Callback); + getMessage(): string; + getWaitTime(): number; + // (undocumented) + payload: Callback; +} + +// @public (undocumented) +export interface ProcessedPropertyError { + // (undocumented) + detail: FailedPolicyRequirement; + // (undocumented) + messages: string[]; +} + +// @public +export class ReCaptchaCallback extends BaseCallback { + constructor(payload: Callback); + getSiteKey(): string; + // (undocumented) + payload: Callback; + setResult(result: string): void; +} + +// @public +export class ReCaptchaEnterpriseCallback extends BaseCallback { + constructor(payload: Callback); + getApiUrl(): string; + getElementClass(): string; + getSiteKey(): string; + // (undocumented) + payload: Callback; + setAction(action: string): void; + setClientError(error: string): void; + setPayload(payload: unknown): void; + setResult(result: string): void; +} + +// @public +export class RedirectCallback extends BaseCallback { + constructor(payload: Callback); + getRedirectUrl(): string; + // (undocumented) + payload: Callback; +} + +export { RequestMiddleware } + +// @public +export interface ResolvedServerConfig { + // (undocumented) + baseUrl: string; + // (undocumented) + paths: { + authenticate: string; + sessions: string; + }; +} + +// @public (undocumented) +export interface ResumeOptions { + // (undocumented) + journey?: string; + // (undocumented) + query?: Record; +} + +// @public +export class SelectIdPCallback extends BaseCallback { + constructor(payload: Callback); + getProviders(): IdPValue[]; + // (undocumented) + payload: Callback; + setProvider(value: string): void; +} + +// @public (undocumented) +export interface StartParam { + // (undocumented) + journey: string; + // (undocumented) + query?: Record; +} + +export { Step } + +export { StepDetail } + +export { StepType } + +// @public +export class SuspendedTextOutputCallback extends TextOutputCallback { + constructor(payload: Callback); + // (undocumented) + payload: Callback; +} + +// @public +export class TermsAndConditionsCallback extends BaseCallback { + constructor(payload: Callback); + getCreateDate(): Date | null; + getTerms(): string; + getVersion(): string; + // (undocumented) + payload: Callback; + setAccepted(accepted?: boolean): void; +} + +// @public +export class TextInputCallback extends BaseCallback { + constructor(payload: Callback); + getPrompt(): string; + // (undocumented) + payload: Callback; + setInput(input: string): void; +} + +// @public +export class TextOutputCallback extends BaseCallback { + constructor(payload: Callback); + getMessage(): string; + getMessageType(): string; + // (undocumented) + payload: Callback; +} + +// @public +export class ValidatedCreatePasswordCallback extends BaseCallback { + constructor(payload: Callback); + getFailedPolicies(): PolicyRequirement[]; + getPolicies(): Record; + getPrompt(): string; + isRequired(): boolean; + // (undocumented) + payload: Callback; + setPassword(password: string): void; + setValidateOnly(value: boolean): void; +} + +// @public +export class ValidatedCreateUsernameCallback extends BaseCallback { + constructor(payload: Callback); + getFailedPolicies(): PolicyRequirement[]; + getPolicies(): Record; + getPrompt(): string; + isRequired(): boolean; + // (undocumented) + payload: Callback; + setName(name: string): void; + setValidateOnly(value: boolean): void; +} + +export { WellknownResponse } + +// (No @packageDocumentation comment for this package) + +```