diff --git a/CHANGELOG.md b/CHANGELOG.md index 33d776414..71421fa76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## 6.7.4 ### Fixes - +- [#1263](https://github.com/okta/okta-auth-js/pull/1263) (IDX) `select-enrollment-channel` remediation now accepts protocol defined inputs, as well as conveniences - [#1262](https://github.com/okta/okta-auth-js/pull/1262) Freezes `broadcast-channel` version at `4.13.0`, `4.14.0` requires node 14+ ## 6.7.3 diff --git a/lib/idx/remediators/SelectEnrollmentChannel.ts b/lib/idx/remediators/SelectEnrollmentChannel.ts index 8c135f012..48eac5959 100644 --- a/lib/idx/remediators/SelectEnrollmentChannel.ts +++ b/lib/idx/remediators/SelectEnrollmentChannel.ts @@ -13,6 +13,7 @@ import { Remediator, RemediationValues } from './Base/Remediator'; import { IdxRemediationValueForm, IdxOption, IdxRemediationValue, IdxContext } from '../types/idx-js'; +import { Authenticator } from '../types'; import { getAuthenticatorFromRemediation } from './util'; import { OktaAuthIdxInterface } from '../../types'; @@ -25,7 +26,18 @@ export class SelectEnrollmentChannel extends Remediator valueKey !== 'channel'); + this.values = super.getValuesAfterProceed(); + delete this.values.authenticators; // required to prevent infinite loops from auto-remediating via values + const filterKey = this.values.channel ? 'channel' : 'authenticator'; + let trimmedValues = Object.keys(this.values).filter(valueKey => valueKey !== filterKey); return trimmedValues.reduce((values, valueKey) => ({...values, [valueKey]: this.values[valueKey]}), {}); } } diff --git a/lib/idx/types/api.ts b/lib/idx/types/api.ts index 10b2a9b10..9a06f0253 100644 --- a/lib/idx/types/api.ts +++ b/lib/idx/types/api.ts @@ -119,6 +119,7 @@ export type Authenticator = { key?: string; methodType?: string; phoneNumber?: string; + channel?: string; }; export function isAuthenticator(obj: any): obj is Authenticator { diff --git a/package.json b/package.json index 4f4490c96..170f12cbd 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "private": true, "name": "@okta/okta-auth-js", "description": "The Okta Auth SDK", - "version": "6.7.3", + "version": "6.7.4", "homepage": "https://github.com/okta/okta-auth-js", "license": "Apache-2.0", "main": "build/cjs/index.js", diff --git a/test/spec/idx/authenticate.ts b/test/spec/idx/authenticate.ts index 042f99a49..ad72798ce 100644 --- a/test/spec/idx/authenticate.ts +++ b/test/spec/idx/authenticate.ts @@ -1967,7 +1967,7 @@ describe('idx/authenticate', () => { }); - it('can get Okta Verify link via SMS', async () => { + it('can get Okta Verify link via SMS (proceed via channel)', async () => { const { authClient, selectAuthenticatorResponse, @@ -2027,6 +2027,73 @@ describe('idx/authenticate', () => { expect(enrollmentChannelDataSmsResponse.proceed).toHaveBeenCalled(); }); + + it('can get Okta Verify link via SMS (proceed via authenticator)', async () => { + const { + authClient, + selectAuthenticatorResponse, + enrollPollResponse, + enrollmentChannelDataSmsResponse, + successResponse + } = testContext; + + chainResponses([ + selectAuthenticatorResponse, + enrollPollResponse, + enrollmentChannelDataSmsResponse, + successResponse + ]); + + jest.spyOn(mocked.introspect, 'introspect') + .mockResolvedValueOnce(selectAuthenticatorResponse) + .mockResolvedValueOnce(enrollPollResponse) + .mockResolvedValueOnce(enrollPollResponse) // submit enrollment channel + .mockResolvedValueOnce(enrollmentChannelDataSmsResponse); + + jest.spyOn(enrollPollResponse, 'proceed'); + jest.spyOn(enrollmentChannelDataSmsResponse, 'proceed'); + + await authenticate(authClient, { + authenticator: AuthenticatorKey.OKTA_VERIFY + }); + let res = await proceed(authClient, { + step: 'select-enrollment-channel' + }); + const { options } = res.nextStep!; + expect(options).toContainEqual({ + label: 'SMS', + value: 'sms' + }); + + res = await proceed(authClient, { + authenticator: { + id: 'string', + channel: 'phoneNumber' + } + }); + const { inputs } = res.nextStep!; + + expect(enrollPollResponse.proceed).toHaveBeenCalledWith( + 'select-enrollment-channel', + expect.objectContaining({ authenticator: expect.objectContaining({ channel: 'phoneNumber' }) }) + ); + + expect(inputs).toContainEqual({ + name: 'phoneNumber', + label: 'Phone Number', + required: true, + type: 'string', + }); + + await proceed(authClient, { + phoneNumber: '+1234' + }); + + expect(enrollmentChannelDataSmsResponse.proceed).toHaveBeenCalledWith( + 'enrollment-channel-data', + expect.objectContaining({ phoneNumber: '+1234' }) + ); + }); }); });