diff --git a/packages/sdks/core-js-sdk/src/sdk/types.ts b/packages/sdks/core-js-sdk/src/sdk/types.ts index 81c1a8758..658bd97a4 100644 --- a/packages/sdks/core-js-sdk/src/sdk/types.ts +++ b/packages/sdks/core-js-sdk/src/sdk/types.ts @@ -14,6 +14,11 @@ type RedirectAuth = { codeChallenge: string; }; +type NativeOptions = { + platform: string; + nativeOAuthProvider?: string; +}; + type AuthMethod = | 'magiclink' | 'enchantedlink' @@ -276,6 +281,8 @@ export type FlowResponse = { options: string; create: boolean; }; + // native data - if the action is 'native' + native?: string; // an error that occurred during flow execution, used for debugging / integrating error?: { code: string; @@ -311,6 +318,7 @@ export type Options = { locale?: string; oidcPrompt?: string; oidcErrorRedirectUri?: string; + nativeOptions?: NativeOptions; }; export type ResponseData = Record; diff --git a/packages/sdks/web-component/src/lib/constants/index.ts b/packages/sdks/web-component/src/lib/constants/index.ts index 05d79ee4d..037ffbe23 100644 --- a/packages/sdks/web-component/src/lib/constants/index.ts +++ b/packages/sdks/web-component/src/lib/constants/index.ts @@ -35,6 +35,7 @@ export const RESPONSE_ACTIONS = { poll: 'poll', webauthnCreate: 'webauthnCreate', webauthnGet: 'webauthnGet', + native: 'native', loadForm: 'loadForm', }; diff --git a/packages/sdks/web-component/src/lib/descope-wc/DescopeWc.ts b/packages/sdks/web-component/src/lib/descope-wc/DescopeWc.ts index f4264af34..24bd80f69 100644 --- a/packages/sdks/web-component/src/lib/descope-wc/DescopeWc.ts +++ b/packages/sdks/web-component/src/lib/descope-wc/DescopeWc.ts @@ -50,6 +50,7 @@ import { } from '../types'; import BaseDescopeWc from './BaseDescopeWc'; import loadSdkScript, { getScriptResultPath } from './sdkScripts'; +import { platform } from 'os'; // this class is responsible for WC flow execution class DescopeWc extends BaseDescopeWc { @@ -95,6 +96,16 @@ class DescopeWc extends BaseDescopeWc { } } + updateNativeState( + native: string, + originOverride: string, + nativeOAuthProvider: string, + ) { + this.flowState.update({ native, originOverride, nativeOAuthProvider }); + } + + nativeComplete = async (_: any) => {}; + async loadSdkScripts() { const flowConfig = await this.getFlowConfig(); const scripts = flowConfig.sdkScripts; @@ -216,6 +227,9 @@ class DescopeWc extends BaseDescopeWc { samlIdpResponseUrl, samlIdpResponseSamlResponse, samlIdpResponseRelayState, + native, + nativeResponse, + nativeOAuthProvider, ...ssoQueryParams } = currentState; @@ -234,6 +248,9 @@ class DescopeWc extends BaseDescopeWc { backupCallbackUri: redirectAuthBackupCallbackUri, } : undefined; + const nativeOptions = native + ? { platform: native, nativeOAuthProvider } + : undefined; // if there is no execution id we should start a new flow if (!executionId) { @@ -276,6 +293,7 @@ class DescopeWc extends BaseDescopeWc { lastAuth: getLastAuth(loginId), abTestingKey, locale: getUserLocale(locale).locale, + nativeOptions, }, conditionInteractionId, '', @@ -420,6 +438,24 @@ class DescopeWc extends BaseDescopeWc { this.#handleSdkResponse(sdkResp); } + if (action === RESPONSE_ACTIONS.native) { + // prepare a callback to receive the response and failure from the Android layer + this.nativeComplete = async (input: any) => { + const sdkResp = await this.sdk.flow.next( + executionId, + stepId, + CUSTOM_INTERACTIONS.submit, + flowConfig.version, + projectConfig.componentsVersion, + input, + ); + this.#handleSdkResponse(sdkResp); + }; + // notify the Android layer that a native action is requested + this.#dispatch('native', nativeResponse); + return; + } + this.#handlePollingResponse( executionId, stepId, @@ -502,6 +538,7 @@ class DescopeWc extends BaseDescopeWc { client: this.client, ...(redirectUrl && { redirectUrl }), locale: getUserLocale(locale).locale, + nativeOptions, }, conditionInteractionId, interactionId, @@ -652,6 +689,7 @@ class DescopeWc extends BaseDescopeWc { webauthn, error, samlIdpResponse, + native, } = sdkResp.data; if (action === RESPONSE_ACTIONS.poll) { @@ -688,6 +726,7 @@ class DescopeWc extends BaseDescopeWc { samlIdpResponseUrl: samlIdpResponse?.url, samlIdpResponseSamlResponse: samlIdpResponse?.samlResponse, samlIdpResponseRelayState: samlIdpResponse?.relayState, + nativeResponse: native, }); }; @@ -997,7 +1036,8 @@ class DescopeWc extends BaseDescopeWc { ...eleDescopeAttrs, ...formData, // 'origin' is required to start webauthn. For now we'll add it to every request - origin: window.location.origin, + origin: + this.flowState.current.originOverride || window.location.origin, }; const flowConfig = await this.getFlowConfig(); diff --git a/packages/sdks/web-component/src/lib/types.ts b/packages/sdks/web-component/src/lib/types.ts index 23baa4a8b..98482b36a 100644 --- a/packages/sdks/web-component/src/lib/types.ts +++ b/packages/sdks/web-component/src/lib/types.ts @@ -80,6 +80,10 @@ export type FlowState = { samlIdpResponseUrl: string; samlIdpResponseSamlResponse: string; samlIdpResponseRelayState: string; + native: string; + nativeResponse: string; + nativeOAuthProvider: string; + originOverride: string; } & SSOQueryParams; export type StepState = { diff --git a/packages/sdks/web-js-sdk/src/sdk/flow.ts b/packages/sdks/web-js-sdk/src/sdk/flow.ts index 9ff3fcb84..1a10f1e76 100644 --- a/packages/sdks/web-js-sdk/src/sdk/flow.ts +++ b/packages/sdks/web-js-sdk/src/sdk/flow.ts @@ -18,6 +18,7 @@ type Options = Pick< | 'locale' | 'oidcPrompt' | 'oidcErrorRedirectUri' + | 'nativeOptions' > & { lastAuth?: Omit; };