@okta/okta-signin-widget 7.16.0 → 7.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/README.md +5 -5
  2. package/dist/css/fonts.css +172 -0
  3. package/dist/css/okta-sign-in.next.css +1 -240
  4. package/dist/css/okta-sign-in.next.css.map +1 -1
  5. package/dist/esm/src/config/config.json.js +1 -1
  6. package/dist/js/okta-sign-in.classic.js +1 -1
  7. package/dist/js/okta-sign-in.classic.min.js +1 -1
  8. package/dist/js/okta-sign-in.js +1 -1
  9. package/dist/js/okta-sign-in.min.js +1 -1
  10. package/dist/js/okta-sign-in.next.js +61 -19
  11. package/dist/js/okta-sign-in.next.js.map +1 -1
  12. package/dist/js/okta-sign-in.next.no-polyfill.js +60 -18
  13. package/dist/js/okta-sign-in.next.no-polyfill.js.map +1 -1
  14. package/dist/js/okta-sign-in.no-polyfill.min.js +1 -1
  15. package/dist/js/okta-sign-in.oie.js +1 -1
  16. package/dist/js/okta-sign-in.oie.min.js +1 -1
  17. package/package.json +10 -5
  18. package/src/config/config.json +1 -1
  19. package/src/v3/components/AuthCoin/AuthCoin.tsx +15 -17
  20. package/src/v3/components/AuthContainer/AuthContainer.tsx +11 -17
  21. package/src/v3/components/AuthContent/AuthContent.tsx +21 -16
  22. package/src/v3/components/AuthHeader/AuthHeader.tsx +18 -19
  23. package/src/v3/components/AuthenticatorButton/AuthenticatorButton.tsx +116 -77
  24. package/src/v3/components/AuthenticatorButton/AuthenticatorButtonList.tsx +9 -3
  25. package/src/v3/components/Button/Button.tsx +16 -20
  26. package/src/v3/components/CaptchaContainer/CaptchaContainer.tsx +1 -1
  27. package/src/v3/components/Checkbox/Checkbox.tsx +33 -82
  28. package/src/v3/components/ConsentHeader/ConsentHeader.tsx +23 -23
  29. package/src/v3/components/Divider/Divider.tsx +2 -2
  30. package/src/v3/components/Form/Accordion.tsx +15 -36
  31. package/src/v3/components/Form/ElementContainer.tsx +6 -3
  32. package/src/v3/components/Form/Form.tsx +2 -4
  33. package/src/v3/components/Form/Layout.tsx +1 -1
  34. package/src/v3/components/Form/LayoutContainer.tsx +4 -2
  35. package/src/v3/components/Heading/Heading.tsx +7 -5
  36. package/src/v3/components/Icon/CustomAppIcon.tsx +13 -15
  37. package/src/v3/components/Icon/CustomOTPIcon.tsx +5 -10
  38. package/src/v3/components/Icon/DuoIcon.tsx +5 -10
  39. package/src/v3/components/Icon/EmailIcon.tsx +5 -10
  40. package/src/v3/components/Icon/GoogleOTPIcon.tsx +5 -10
  41. package/src/v3/components/Icon/IDPIcon.tsx +5 -10
  42. package/src/v3/components/Icon/OktaVerifyIcon.tsx +0 -7
  43. package/src/v3/components/Icon/OnPremMFAIcon.tsx +5 -10
  44. package/src/v3/components/Icon/PasswordIcon.tsx +5 -10
  45. package/src/v3/components/Icon/PhoneIcon.tsx +5 -10
  46. package/src/v3/components/Icon/RSAIcon.tsx +6 -11
  47. package/src/v3/components/Icon/SecurityKeyOrBiometricsIcon.tsx +5 -10
  48. package/src/v3/components/Icon/SecurityQuestionIcon.tsx +5 -10
  49. package/src/v3/components/Icon/SmartCardIcon.tsx +5 -10
  50. package/src/v3/components/Icon/SymantecIcon.tsx +5 -10
  51. package/src/v3/components/Icon/YubiKeyIcon.tsx +5 -10
  52. package/src/v3/components/Icon/index.tsx +0 -2
  53. package/src/v3/components/IdentifierContainer/IdentifierContainer.tsx +31 -47
  54. package/src/v3/components/Image/Image.tsx +42 -0
  55. package/src/v3/{src/components/CustomPluginsOdysseyCacheProvider → components/Image}/index.tsx +2 -2
  56. package/src/v3/components/ImageWithText/ImageWithText.tsx +7 -4
  57. package/src/v3/components/Images/AppIcon.tsx +16 -46
  58. package/src/v3/components/Images/DeviceIcon.tsx +16 -32
  59. package/src/v3/components/Images/LocationIcon.tsx +16 -26
  60. package/src/v3/components/Images/PhoneIcon.tsx +34 -29
  61. package/src/v3/components/Images/YubikeyDemoImage.tsx +32 -27
  62. package/src/v3/components/Images/index.tsx +0 -1
  63. package/src/v3/components/InfoBox/InfoBox.tsx +12 -12
  64. package/src/v3/components/InfoSection/InfoSection.tsx +20 -14
  65. package/src/v3/components/InformationalText/InformationalText.tsx +16 -6
  66. package/src/v3/components/InputPassword/InputPassword.tsx +31 -164
  67. package/src/v3/components/InputText/InputText.tsx +27 -103
  68. package/src/v3/components/LaunchAuthenticatorButton/LaunchAuthenticatorButton.tsx +14 -26
  69. package/src/v3/components/Link/Link.tsx +8 -20
  70. package/src/v3/components/List/List.tsx +16 -12
  71. package/src/v3/components/PIVButton/PIVButton.tsx +10 -8
  72. package/src/v3/components/PasswordRequirements/Icon.tsx +17 -23
  73. package/src/v3/components/PasswordRequirements/PasswordMatches.tsx +9 -2
  74. package/src/v3/components/PasswordRequirements/PasswordRequirementListItem.tsx +6 -5
  75. package/src/v3/components/PasswordRequirements/PasswordRequirements.tsx +5 -3
  76. package/src/v3/components/PhoneAuthenticator/PhoneAuthenticator.tsx +53 -137
  77. package/src/v3/components/QRCode/QRCode.tsx +27 -20
  78. package/src/v3/components/Radio/Radio.tsx +31 -93
  79. package/src/v3/components/ReminderPrompt/ReminderPrompt.tsx +9 -12
  80. package/src/v3/components/Select/Select.tsx +45 -92
  81. package/src/v3/components/Spinner/Spinner.tsx +6 -8
  82. package/src/v3/components/StepperButton/StepperButton.tsx +6 -10
  83. package/src/v3/components/StepperLink/StepperLink.tsx +1 -1
  84. package/src/v3/components/StepperRadio/StepperRadio.tsx +22 -43
  85. package/src/v3/components/TextWithActionLink/TextWithActionLink.tsx +1 -1
  86. package/src/v3/components/Title/Title.tsx +5 -9
  87. package/src/v3/components/WebAuthNSubmitButton/WebAuthNSubmitButton.tsx +10 -9
  88. package/src/v3/components/Widget/GlobalStyles.tsx +16 -21
  89. package/src/v3/components/Widget/index.tsx +51 -36
  90. package/src/v3/components/Widget/style.scss +295 -0
  91. package/src/v3/components/WidgetMessageContainer/WidgetMessageContainer.tsx +11 -8
  92. package/src/v3/components/hocs/withFormValidationState.tsx +2 -5
  93. package/src/v3/jest.config.js +1 -0
  94. package/src/v3/jest.setup.js +1 -0
  95. package/src/v3/package.json +11 -7
  96. package/src/v3/screenshots/base/UI_demo/UI_demo_RTL_VRT.png +0 -0
  97. package/src/v3/screenshots/base/UI_demo/UI_demo_VRT.png +0 -0
  98. package/src/v3/src/components/AuthCoin/AuthCoin.tsx +15 -17
  99. package/src/v3/src/components/AuthCoin/__snapshots__/AuthCoin.test.tsx.snap +20 -47
  100. package/src/v3/src/components/AuthContainer/AuthContainer.tsx +11 -17
  101. package/src/v3/src/components/AuthContent/AuthContent.tsx +21 -16
  102. package/src/v3/src/components/AuthHeader/AuthHeader.tsx +18 -19
  103. package/src/v3/src/components/AuthenticatorButton/AuthenticatorButton.tsx +116 -77
  104. package/src/v3/src/components/AuthenticatorButton/AuthenticatorButtonList.tsx +9 -3
  105. package/src/v3/src/components/Button/Button.tsx +16 -20
  106. package/src/v3/src/components/CaptchaContainer/CaptchaContainer.tsx +1 -1
  107. package/src/v3/src/components/Checkbox/Checkbox.tsx +33 -82
  108. package/src/v3/src/components/ConsentHeader/ConsentHeader.tsx +23 -23
  109. package/src/v3/src/components/Divider/Divider.tsx +2 -2
  110. package/src/v3/src/components/Form/Accordion.tsx +15 -36
  111. package/src/v3/src/components/Form/ElementContainer.tsx +6 -3
  112. package/src/v3/src/components/Form/Form.tsx +2 -4
  113. package/src/v3/src/components/Form/Layout.tsx +1 -1
  114. package/src/v3/src/components/Form/LayoutContainer.tsx +4 -2
  115. package/src/v3/src/components/Heading/Heading.tsx +7 -5
  116. package/src/v3/src/components/Icon/CustomAppIcon.tsx +13 -15
  117. package/src/v3/src/components/Icon/CustomOTPIcon.tsx +5 -10
  118. package/src/v3/src/components/Icon/DuoIcon.tsx +5 -10
  119. package/src/v3/src/components/Icon/EmailIcon.tsx +5 -10
  120. package/src/v3/src/components/Icon/GoogleOTPIcon.tsx +5 -10
  121. package/src/v3/src/components/Icon/IDPIcon.tsx +5 -10
  122. package/src/v3/src/components/Icon/OktaVerifyIcon.tsx +0 -7
  123. package/src/v3/src/components/Icon/OnPremMFAIcon.tsx +5 -10
  124. package/src/v3/src/components/Icon/PasswordIcon.tsx +5 -10
  125. package/src/v3/src/components/Icon/PhoneIcon.tsx +5 -10
  126. package/src/v3/src/components/Icon/RSAIcon.tsx +6 -11
  127. package/src/v3/src/components/Icon/SecurityKeyOrBiometricsIcon.tsx +5 -10
  128. package/src/v3/src/components/Icon/SecurityQuestionIcon.tsx +5 -10
  129. package/src/v3/src/components/Icon/SmartCardIcon.tsx +5 -10
  130. package/src/v3/src/components/Icon/SymantecIcon.tsx +5 -10
  131. package/src/v3/src/components/Icon/YubiKeyIcon.tsx +5 -10
  132. package/src/v3/src/components/Icon/index.tsx +0 -2
  133. package/src/v3/src/components/IdentifierContainer/IdentifierContainer.tsx +31 -47
  134. package/src/v3/src/components/Image/Image.tsx +42 -0
  135. package/src/v3/{components/CustomPluginsOdysseyCacheProvider → src/components/Image}/index.tsx +2 -2
  136. package/src/v3/src/components/ImageWithText/ImageWithText.tsx +7 -4
  137. package/src/v3/src/components/Images/AppIcon.tsx +16 -46
  138. package/src/v3/src/components/Images/DeviceIcon.tsx +16 -32
  139. package/src/v3/src/components/Images/LocationIcon.tsx +16 -26
  140. package/src/v3/src/components/Images/PhoneIcon.tsx +34 -29
  141. package/src/v3/src/components/Images/YubikeyDemoImage.tsx +32 -27
  142. package/src/v3/src/components/Images/index.tsx +0 -1
  143. package/src/v3/src/components/InfoBox/InfoBox.tsx +12 -12
  144. package/src/v3/src/components/InfoSection/InfoSection.tsx +20 -14
  145. package/src/v3/src/components/InformationalText/InformationalText.tsx +16 -6
  146. package/src/v3/src/components/InputPassword/InputPassword.tsx +31 -164
  147. package/src/v3/src/components/InputText/InputText.tsx +27 -103
  148. package/src/v3/src/components/LaunchAuthenticatorButton/LaunchAuthenticatorButton.tsx +14 -26
  149. package/src/v3/src/components/Link/Link.tsx +8 -20
  150. package/src/v3/src/components/List/List.tsx +16 -12
  151. package/src/v3/src/components/PIVButton/PIVButton.tsx +10 -8
  152. package/src/v3/src/components/PasswordRequirements/Icon.tsx +17 -23
  153. package/src/v3/src/components/PasswordRequirements/PasswordMatches.tsx +9 -2
  154. package/src/v3/src/components/PasswordRequirements/PasswordRequirementListItem.tsx +6 -5
  155. package/src/v3/src/components/PasswordRequirements/PasswordRequirements.tsx +5 -3
  156. package/src/v3/src/components/PhoneAuthenticator/PhoneAuthenticator.tsx +53 -137
  157. package/src/v3/src/components/QRCode/QRCode.tsx +27 -20
  158. package/src/v3/src/components/Radio/Radio.tsx +31 -93
  159. package/src/v3/src/components/ReminderPrompt/ReminderPrompt.tsx +9 -12
  160. package/src/v3/src/components/ReminderPrompt/__snapshots__/ReminderPrompt.test.tsx.snap +37 -17
  161. package/src/v3/src/components/Select/Select.tsx +45 -92
  162. package/src/v3/src/components/Spinner/Spinner.tsx +6 -8
  163. package/src/v3/src/components/StepperButton/StepperButton.tsx +6 -10
  164. package/src/v3/src/components/StepperLink/StepperLink.tsx +1 -1
  165. package/src/v3/src/components/StepperRadio/StepperRadio.tsx +22 -43
  166. package/src/v3/src/components/TextWithActionLink/TextWithActionLink.tsx +1 -1
  167. package/src/v3/src/components/Title/Title.tsx +5 -9
  168. package/src/v3/src/components/WebAuthNSubmitButton/WebAuthNSubmitButton.tsx +10 -9
  169. package/src/v3/src/components/Widget/GlobalStyles.tsx +16 -21
  170. package/src/v3/src/components/Widget/index.tsx +51 -36
  171. package/src/v3/src/components/Widget/style.scss +295 -0
  172. package/src/v3/src/components/WidgetMessageContainer/WidgetMessageContainer.tsx +11 -8
  173. package/src/v3/src/components/hocs/withFormValidationState.tsx +2 -5
  174. package/src/v3/src/transformer/button/__snapshots__/transformIDPButtons.test.ts.snap +0 -2
  175. package/src/v3/src/transformer/i18n/__snapshots__/transformAuthenticatorButton.test.ts.snap +4 -4
  176. package/src/v3/src/transformer/i18n/transformAuthenticatorButton.test.ts +3 -3
  177. package/src/v3/src/transformer/i18n/transformAuthenticatorButton.ts +18 -2
  178. package/src/v3/src/transformer/layout/development/transformEnumerateComponents.ts +72 -5
  179. package/src/v3/src/transformer/layout/idp/__snapshots__/transformIdpRedirect.test.ts.snap +4 -4
  180. package/src/v3/src/transformer/selectAuthenticator/__snapshots__/transformSelectAuthenticatorVerify.test.ts.snap +0 -3
  181. package/src/v3/src/transformer/selectAuthenticator/__snapshots__/transformSelectOVCustomAppMethodVerify.test.ts.snap +0 -1
  182. package/src/v3/src/transformer/selectAuthenticator/__snapshots__/utils.test.ts.snap +163 -42
  183. package/src/v3/src/transformer/selectAuthenticator/transformSelectAuthenticatorEnroll.ts +7 -1
  184. package/src/v3/src/transformer/selectAuthenticator/transformSelectAuthenticatorVerify.ts +0 -1
  185. package/src/v3/src/transformer/selectAuthenticator/transformSelectOVCustomAppMethodVerify.ts +0 -1
  186. package/src/v3/src/transformer/selectAuthenticator/utils.test.ts +117 -39
  187. package/src/v3/src/transformer/selectAuthenticator/utils.ts +102 -58
  188. package/src/v3/src/transformer/terminal/transformEmailMagicLinkOTPOnlyElements.ts +1 -3
  189. package/src/v3/src/transformer/uischema/transform.test.ts +0 -6
  190. package/src/v3/src/transformer/uischema/transform.ts +0 -2
  191. package/src/v3/src/{components/FieldLevelMessageContainer/index.tsx → types/image.ts} +10 -3
  192. package/src/v3/src/types/index.ts +1 -0
  193. package/src/v3/src/types/schema.ts +2 -1
  194. package/src/v3/src/types/widget.ts +3 -3
  195. package/src/v3/src/util/buildFieldLevelErrorMessages.ts +48 -0
  196. package/src/v3/src/util/formUtils.ts +5 -17
  197. package/src/v3/src/util/htmlContentParserUtils.tsx +3 -1
  198. package/src/v3/src/util/index.ts +2 -0
  199. package/src/v3/src/util/isLtrField.ts +22 -0
  200. package/src/v3/src/util/languageUtils.ts +14 -0
  201. package/src/v3/src/util/leonardo.d.ts +571 -0
  202. package/src/v3/src/util/mergeThemes.test.tsx +20 -7
  203. package/src/v3/src/util/mergeThemes.ts +32 -1
  204. package/src/v3/src/util/stylisPlugins.ts +21 -0
  205. package/src/v3/src/util/theme.test.ts +63 -187
  206. package/src/v3/src/util/theme.ts +274 -247
  207. package/src/v3/svgo.config.js +0 -6
  208. package/src/v3/transformer/i18n/transformAuthenticatorButton.ts +18 -2
  209. package/src/v3/transformer/layout/development/transformEnumerateComponents.ts +72 -5
  210. package/src/v3/transformer/selectAuthenticator/transformSelectAuthenticatorEnroll.ts +7 -1
  211. package/src/v3/transformer/selectAuthenticator/transformSelectAuthenticatorVerify.ts +0 -1
  212. package/src/v3/transformer/selectAuthenticator/transformSelectOVCustomAppMethodVerify.ts +0 -1
  213. package/src/v3/transformer/selectAuthenticator/utils.ts +102 -58
  214. package/src/v3/transformer/terminal/transformEmailMagicLinkOTPOnlyElements.ts +1 -3
  215. package/src/v3/transformer/uischema/transform.ts +0 -2
  216. package/src/v3/tsconfig.base.json +3 -0
  217. package/src/v3/{components/FieldLevelMessageContainer/index.tsx → types/image.ts} +10 -3
  218. package/src/v3/types/index.ts +1 -0
  219. package/src/v3/types/schema.ts +2 -1
  220. package/src/v3/types/widget.ts +3 -3
  221. package/src/v3/util/buildFieldLevelErrorMessages.ts +48 -0
  222. package/src/v3/util/formUtils.ts +5 -17
  223. package/src/v3/util/htmlContentParserUtils.tsx +3 -1
  224. package/src/v3/util/index.ts +2 -0
  225. package/src/v3/util/isLtrField.ts +22 -0
  226. package/src/v3/util/languageUtils.ts +14 -0
  227. package/src/v3/util/leonardo.d.ts +571 -0
  228. package/src/v3/util/mergeThemes.ts +32 -1
  229. package/src/v3/util/stylisPlugins.ts +21 -0
  230. package/src/v3/util/theme.ts +274 -247
  231. package/src/v3/components/CustomPluginsOdysseyCacheProvider/CustomPluginsOdysseyCacheProvider.tsx +0 -66
  232. package/src/v3/components/FieldLevelMessageContainer/FieldLevelMessageContainer.tsx +0 -55
  233. package/src/v3/components/Icon/CheckCircle.tsx +0 -30
  234. package/src/v3/components/Icon/RightArrowIcon.tsx +0 -30
  235. package/src/v3/components/Images/MobileDeviceIcon.tsx +0 -38
  236. package/src/v3/components/Widget/style.css +0 -181
  237. package/src/v3/src/components/CustomPluginsOdysseyCacheProvider/CustomPluginsOdysseyCacheProvider.tsx +0 -66
  238. package/src/v3/src/components/FieldLevelMessageContainer/FieldLevelMessageContainer.tsx +0 -55
  239. package/src/v3/src/components/Icon/CheckCircle.tsx +0 -30
  240. package/src/v3/src/components/Icon/RightArrowIcon.tsx +0 -30
  241. package/src/v3/src/components/Images/MobileDeviceIcon.tsx +0 -38
  242. package/src/v3/src/components/Widget/style.css +0 -181
  243. package/src/v3/src/transformer/uischema/setLtrFields.ts +0 -41
  244. package/src/v3/src/util/designTokens.ts +0 -249
  245. package/src/v3/transformer/uischema/setLtrFields.ts +0 -41
  246. package/src/v3/util/designTokens.ts +0 -249
@@ -11,7 +11,7 @@
11
11
  */
12
12
 
13
13
  import { Input } from '@okta/okta-auth-js';
14
- import { IdxOption } from '@okta/okta-auth-js/types/lib/idx/types/idx-js';
14
+ import { IdxAuthenticator, IdxOption } from '@okta/okta-auth-js/types/lib/idx/types/idx-js';
15
15
  import { AUTHENTICATOR_ENROLLMENT_DESCR_KEY_MAP, AUTHENTICATOR_KEY, IDX_STEP } from 'src/constants';
16
16
  import { ButtonType } from 'src/types';
17
17
 
@@ -23,7 +23,7 @@ import {
23
23
  } from './utils';
24
24
 
25
25
  describe('Select Authenticator Utility Tests', () => {
26
- const stepName = IDX_STEP.SELECT_AUTHENTICATOR_ENROLL;
26
+ const stepName = IDX_STEP.SELECT_AUTHENTICATOR_AUTHENTICATE;
27
27
  describe('getAppAuthenticatorMethodButtonElements Tests', () => {
28
28
  it('should return an empty array when an empty array of options is provided', () => {
29
29
  expect(getAppAuthenticatorMethodButtonElements({ name: 'authenticator' }, stepName)).toEqual([]);
@@ -45,44 +45,42 @@ describe('Select Authenticator Utility Tests', () => {
45
45
  expect(getAppAuthenticatorMethodButtonElements(authenticator, stepName)).toEqual([
46
46
  {
47
47
  type: 'AuthenticatorButton',
48
- label: options[0].label,
48
+ label: 'oie.okta_verify.label',
49
49
  id: 'auth_btn_okta_verify_totp',
50
- noTranslate: false,
51
50
  options: {
52
51
  key: AUTHENTICATOR_KEY.OV,
53
52
  ctaLabel: 'oie.verify.authenticator.button.text',
54
53
  includeData: true,
55
54
  includeImmutableData: false,
56
- step: 'select-authenticator-enroll',
55
+ step: 'select-authenticator-authenticate',
57
56
  type: ButtonType.BUTTON,
58
57
  actionParams: {
59
58
  'authenticator.id': 'abcde1234',
60
59
  'authenticator.methodType': options[0].value,
61
60
  },
62
- description: 'oie.okta_verify.label',
63
61
  ariaLabel: 'oie.select.authenticator.okta_verify.totp.label',
62
+ description: options[0].label,
64
63
  dataSe: `okta_verify-${options[0].value}`,
65
64
  iconName: 'okta_verify_0',
66
65
  },
67
66
  },
68
67
  {
69
68
  type: 'AuthenticatorButton',
70
- label: options[1].label,
69
+ label: 'oie.okta_verify.label',
71
70
  id: 'auth_btn_okta_verify_push',
72
- noTranslate: false,
73
71
  options: {
74
72
  key: AUTHENTICATOR_KEY.OV,
75
73
  ctaLabel: 'oie.verify.authenticator.button.text',
76
74
  includeData: true,
77
75
  includeImmutableData: false,
78
- step: 'select-authenticator-enroll',
76
+ step: 'select-authenticator-authenticate',
79
77
  type: ButtonType.BUTTON,
80
78
  actionParams: {
81
79
  'authenticator.id': 'abcde1234',
82
80
  'authenticator.methodType': options[1].value,
83
81
  },
84
- description: 'oie.okta_verify.label',
85
82
  ariaLabel: 'oie.select.authenticator.okta_verify.push.label',
83
+ description: options[1].label,
86
84
  dataSe: `okta_verify-${options[1].value}`,
87
85
  iconName: 'okta_verify_1',
88
86
  },
@@ -112,66 +110,63 @@ describe('Select Authenticator Utility Tests', () => {
112
110
  )).toEqual([
113
111
  {
114
112
  type: 'AuthenticatorButton',
115
- label: options[2].label,
113
+ label: 'oie.okta_verify.label',
116
114
  id: 'auth_btn_okta_verify_signed_nonce',
117
- noTranslate: false,
118
115
  options: {
119
116
  key: AUTHENTICATOR_KEY.OV,
120
117
  ctaLabel: 'oie.verify.authenticator.button.text',
121
118
  includeData: true,
122
119
  includeImmutableData: false,
123
- step: 'select-authenticator-enroll',
120
+ step: 'select-authenticator-authenticate',
124
121
  type: ButtonType.BUTTON,
125
122
  actionParams: {
126
123
  'authenticator.id': 'abcde1234',
127
124
  'authenticator.methodType': options[2].value,
128
125
  },
129
- description: 'oie.okta_verify.label',
130
126
  ariaLabel: 'oie.select.authenticator.okta_verify.signed_nonce.label',
127
+ description: options[2].label,
131
128
  dataSe: `okta_verify-${options[2].value}`,
132
129
  iconName: 'okta_verify_2',
133
130
  },
134
131
  },
135
132
  {
136
133
  type: 'AuthenticatorButton',
137
- label: options[0].label,
134
+ label: 'oie.okta_verify.label',
138
135
  id: 'auth_btn_okta_verify_totp',
139
- noTranslate: false,
140
136
  options: {
141
137
  key: AUTHENTICATOR_KEY.OV,
142
138
  ctaLabel: 'oie.verify.authenticator.button.text',
143
139
  includeData: true,
144
140
  includeImmutableData: false,
145
- step: 'select-authenticator-enroll',
141
+ step: 'select-authenticator-authenticate',
146
142
  type: ButtonType.BUTTON,
147
143
  actionParams: {
148
144
  'authenticator.id': 'abcde1234',
149
145
  'authenticator.methodType': options[0].value,
150
146
  },
151
- description: 'oie.okta_verify.label',
152
147
  ariaLabel: 'oie.select.authenticator.okta_verify.totp.label',
148
+ description: options[0].label,
153
149
  dataSe: `okta_verify-${options[0].value}`,
154
150
  iconName: 'okta_verify_0',
155
151
  },
156
152
  },
157
153
  {
158
154
  type: 'AuthenticatorButton',
159
- label: options[1].label,
155
+ label: 'oie.okta_verify.label',
160
156
  id: 'auth_btn_okta_verify_push',
161
- noTranslate: false,
162
157
  options: {
163
158
  key: AUTHENTICATOR_KEY.OV,
164
159
  ctaLabel: 'oie.verify.authenticator.button.text',
165
160
  includeData: true,
166
161
  includeImmutableData: false,
167
- step: 'select-authenticator-enroll',
162
+ step: 'select-authenticator-authenticate',
168
163
  type: ButtonType.BUTTON,
169
164
  actionParams: {
170
165
  'authenticator.id': 'abcde1234',
171
166
  'authenticator.methodType': options[1].value,
172
167
  },
173
- description: 'oie.okta_verify.label',
174
168
  ariaLabel: 'oie.select.authenticator.okta_verify.push.label',
169
+ description: options[1].label,
175
170
  dataSe: `okta_verify-${options[1].value}`,
176
171
  iconName: 'okta_verify_1',
177
172
  },
@@ -250,7 +245,7 @@ describe('Select Authenticator Utility Tests', () => {
250
245
  id: '',
251
246
  type: '',
252
247
  methods: [{ type: '' }],
253
- displayName: '',
248
+ displayName: 'DisplayName',
254
249
  key: AUTHENTICATOR_KEY[key],
255
250
  profile: {},
256
251
  },
@@ -271,7 +266,15 @@ describe('Select Authenticator Utility Tests', () => {
271
266
  const currentOption = authenticatorOptionValues
272
267
  .find(({ options: { key: authKey } }) => authKey === option.relatesTo?.key);
273
268
  expect(currentOption?.options.key).toBe(option.relatesTo?.key);
274
- expect(currentOption?.label).toBe(option.label);
269
+ let expectedLabel;
270
+ if (option.relatesTo?.key === AUTHENTICATOR_KEY.CUSTOM_APP) {
271
+ expectedLabel = 'DisplayName';
272
+ } else if (option.relatesTo?.key === AUTHENTICATOR_KEY.OV) {
273
+ expectedLabel = 'oie.okta_verify.label';
274
+ } else {
275
+ expectedLabel = option.label;
276
+ }
277
+ expect(currentOption?.label).toBe(expectedLabel);
275
278
  expect(currentOption?.options.ctaLabel)
276
279
  .toBe('oie.verify.authenticator.button.text');
277
280
  });
@@ -352,11 +355,13 @@ describe('Select Authenticator Utility Tests', () => {
352
355
  expect(authenticatorOptionValues).toMatchSnapshot();
353
356
  expect(authenticatorOptionValues.length).toBe(2);
354
357
  expect(authenticatorOptionValues[0].options.key).toBe(AUTHENTICATOR_KEY.OV);
355
- expect(authenticatorOptionValues[0].label).toBe('Code');
358
+ expect(authenticatorOptionValues[0].label).toBe('oie.okta_verify.label');
359
+ expect(authenticatorOptionValues[0].options.description).toBe('Code');
356
360
  expect(authenticatorOptionValues[0].options.ctaLabel).toBe('oie.verify.authenticator.button.text');
357
361
  expect(authenticatorOptionValues[0].options.actionParams?.['authenticator.methodType']).toBe('totp');
358
362
  expect(authenticatorOptionValues[1].options.key).toBe(AUTHENTICATOR_KEY.OV);
359
- expect(authenticatorOptionValues[1].label).toBe('Push');
363
+ expect(authenticatorOptionValues[1].label).toBe('oie.okta_verify.label');
364
+ expect(authenticatorOptionValues[1].options.description).toBe('Push');
360
365
  expect(authenticatorOptionValues[1].options.ctaLabel).toBe('oie.verify.authenticator.button.text');
361
366
  expect(authenticatorOptionValues[1].options.actionParams?.['authenticator.methodType']).toBe('push');
362
367
  });
@@ -434,15 +439,18 @@ describe('Select Authenticator Utility Tests', () => {
434
439
  expect(authenticatorOptionValues).toMatchSnapshot();
435
440
  expect(authenticatorOptionValues.length).toBe(4);
436
441
  expect(authenticatorOptionValues[0].options.key).toBe(AUTHENTICATOR_KEY.OV);
437
- expect(authenticatorOptionValues[0].label).toBe('Fastpass');
442
+ expect(authenticatorOptionValues[0].label).toBe('oie.okta_verify.label');
443
+ expect(authenticatorOptionValues[0].options.description).toBe('Fastpass');
438
444
  expect(authenticatorOptionValues[0].options.ctaLabel).toBe('oie.verify.authenticator.button.text');
439
445
  expect(authenticatorOptionValues[0].options.actionParams?.['authenticator.methodType']).toBe('signed_nonce');
440
446
  expect(authenticatorOptionValues[1].options.key).toBe(AUTHENTICATOR_KEY.OV);
441
- expect(authenticatorOptionValues[1].label).toBe('Code');
447
+ expect(authenticatorOptionValues[1].label).toBe('oie.okta_verify.label');
448
+ expect(authenticatorOptionValues[1].options.description).toBe('Code');
442
449
  expect(authenticatorOptionValues[1].options.ctaLabel).toBe('oie.verify.authenticator.button.text');
443
450
  expect(authenticatorOptionValues[1].options.actionParams?.['authenticator.methodType']).toBe('totp');
444
451
  expect(authenticatorOptionValues[2].options.key).toBe(AUTHENTICATOR_KEY.OV);
445
- expect(authenticatorOptionValues[2].label).toBe('Push');
452
+ expect(authenticatorOptionValues[2].label).toBe('oie.okta_verify.label');
453
+ expect(authenticatorOptionValues[2].options.description).toBe('Push');
446
454
  expect(authenticatorOptionValues[2].options.ctaLabel).toBe('oie.verify.authenticator.button.text');
447
455
  expect(authenticatorOptionValues[2].options.actionParams?.['authenticator.methodType']).toBe('push');
448
456
 
@@ -495,11 +503,13 @@ describe('Select Authenticator Utility Tests', () => {
495
503
  expect(authenticatorOptionValues).toMatchSnapshot();
496
504
  expect(authenticatorOptionValues.length).toBe(4);
497
505
  expect(authenticatorOptionValues[0].options.key).toBe(AUTHENTICATOR_KEY.OV);
498
- expect(authenticatorOptionValues[0].label).toBe('Code');
506
+ expect(authenticatorOptionValues[0].label).toBe('oie.okta_verify.label');
507
+ expect(authenticatorOptionValues[0].options.description).toBe('Code');
499
508
  expect(authenticatorOptionValues[0].options.ctaLabel).toBe('oie.verify.authenticator.button.text');
500
509
  expect(authenticatorOptionValues[0].options.actionParams?.['authenticator.methodType']).toBe('totp');
501
510
  expect(authenticatorOptionValues[1].options.key).toBe(AUTHENTICATOR_KEY.OV);
502
- expect(authenticatorOptionValues[1].label).toBe('Push');
511
+ expect(authenticatorOptionValues[1].label).toBe('oie.okta_verify.label');
512
+ expect(authenticatorOptionValues[1].options.description).toBe('Push');
503
513
  expect(authenticatorOptionValues[1].options.ctaLabel).toBe('oie.verify.authenticator.button.text');
504
514
  expect(authenticatorOptionValues[1].options.actionParams?.['authenticator.methodType']).toBe('push');
505
515
 
@@ -509,7 +519,8 @@ describe('Select Authenticator Utility Tests', () => {
509
519
  .toBe('oie.verify.authenticator.button.text');
510
520
  expect(authenticatorOptionValues[2].options.description).toBe('216XXXXX43');
511
521
  expect(authenticatorOptionValues[3].options.key).toBe(AUTHENTICATOR_KEY.OV);
512
- expect(authenticatorOptionValues[3].label).toBe('Fastpass');
522
+ expect(authenticatorOptionValues[3].label).toBe('oie.okta_verify.label');
523
+ expect(authenticatorOptionValues[3].options.description).toBe('Fastpass');
513
524
  expect(authenticatorOptionValues[3].options.ctaLabel).toBe('oie.verify.authenticator.button.text');
514
525
  expect(authenticatorOptionValues[3].options.actionParams?.['authenticator.methodType']).toBe('signed_nonce');
515
526
  });
@@ -549,7 +560,7 @@ describe('Select Authenticator Utility Tests', () => {
549
560
  expect(authenticatorOptionValues).toMatchSnapshot();
550
561
  expect(authenticatorOptionValues.length).toBe(2);
551
562
  expect(authenticatorOptionValues[0].options.key).toBe(AUTHENTICATOR_KEY.OV);
552
- expect(authenticatorOptionValues[0].label).toBe('Okta Verify');
563
+ expect(authenticatorOptionValues[0].label).toBe('oie.okta_verify.label');
553
564
  expect(authenticatorOptionValues[0].options.ctaLabel).toBe('oie.verify.authenticator.button.text');
554
565
  expect(authenticatorOptionValues[0].options.actionParams?.['authenticator.methodType']).toBe('signed_nonce');
555
566
  expect(authenticatorOptionValues[1].options.key).toBe(AUTHENTICATOR_KEY.PHONE);
@@ -600,11 +611,13 @@ describe('Select Authenticator Utility Tests', () => {
600
611
  expect(authenticatorOptionValues).toMatchSnapshot();
601
612
  expect(authenticatorOptionValues.length).toBe(3);
602
613
  expect(authenticatorOptionValues[0].options.key).toBe(AUTHENTICATOR_KEY.OV);
603
- expect(authenticatorOptionValues[0].label).toBe('Code');
614
+ expect(authenticatorOptionValues[0].label).toBe('oie.okta_verify.label');
615
+ expect(authenticatorOptionValues[0].options.description).toBe('Code');
604
616
  expect(authenticatorOptionValues[0].options.ctaLabel).toBe('oie.verify.authenticator.button.text');
605
617
  expect(authenticatorOptionValues[0].options.actionParams?.['authenticator.methodType']).toBe('totp');
606
618
  expect(authenticatorOptionValues[1].options.key).toBe(AUTHENTICATOR_KEY.OV);
607
- expect(authenticatorOptionValues[1].label).toBe('Push');
619
+ expect(authenticatorOptionValues[1].label).toBe('oie.okta_verify.label');
620
+ expect(authenticatorOptionValues[1].options.description).toBe('Push');
608
621
  expect(authenticatorOptionValues[1].options.ctaLabel).toBe('oie.verify.authenticator.button.text');
609
622
  expect(authenticatorOptionValues[1].options.actionParams?.['authenticator.methodType']).toBe('push');
610
623
 
@@ -634,7 +647,7 @@ describe('Select Authenticator Utility Tests', () => {
634
647
  id: '',
635
648
  type: '',
636
649
  methods: [{ type: '' }],
637
- displayName: '',
650
+ displayName: 'DisplayName',
638
651
  key: AUTHENTICATOR_KEY[key],
639
652
  profile: {},
640
653
  },
@@ -651,7 +664,15 @@ describe('Select Authenticator Utility Tests', () => {
651
664
  const currentOption = authenticatorOptionValues
652
665
  .find(({ options: { key: authKey } }) => authKey === option.relatesTo?.key);
653
666
  expect(currentOption?.options.key).toBe(option.relatesTo?.key);
654
- expect(currentOption?.label).toBe(option.label);
667
+ let expectedLabel;
668
+ if (option.relatesTo?.key === AUTHENTICATOR_KEY.CUSTOM_APP) {
669
+ expectedLabel = 'DisplayName';
670
+ } else if (option.relatesTo?.key === AUTHENTICATOR_KEY.OV) {
671
+ expectedLabel = 'oie.okta_verify.label';
672
+ } else {
673
+ expectedLabel = option.label;
674
+ }
675
+ expect(currentOption?.label).toBe(expectedLabel);
655
676
  expect(currentOption?.options.ctaLabel)
656
677
  .toBe('oie.enroll.authenticator.button.text');
657
678
  expect(currentOption?.options.description)
@@ -712,12 +733,69 @@ describe('Select Authenticator Utility Tests', () => {
712
733
  expect(authenticatorOptionValues).toMatchSnapshot();
713
734
  expect(authenticatorOptionValues.length).toBe(2);
714
735
  expect(authenticatorOptionValues[0].options.key).toBe(AUTHENTICATOR_KEY.OV);
715
- expect(authenticatorOptionValues[0].label).toBe('Code');
736
+ expect(authenticatorOptionValues[0].label).toBe('oie.okta_verify.label');
737
+ expect(authenticatorOptionValues[0].options.description).toBe('oie.okta_verify.authenticator.description');
716
738
  expect(authenticatorOptionValues[0].options.ctaLabel).toBe('oie.enroll.authenticator.button.text');
717
739
  expect(authenticatorOptionValues[0].options.actionParams!['authenticator.methodType']).toBe('totp');
718
- expect(authenticatorOptionValues[1].label).toBe('Push');
740
+ expect(authenticatorOptionValues[1].label).toBe('oie.okta_verify.label');
741
+ expect(authenticatorOptionValues[1].options.description).toBe('oie.okta_verify.authenticator.description');
719
742
  expect(authenticatorOptionValues[1].options.ctaLabel).toBe('oie.enroll.authenticator.button.text');
720
743
  expect(authenticatorOptionValues[1].options.actionParams!['authenticator.methodType']).toBe('push');
721
744
  });
745
+
746
+ it('should detect authenticator options for additional enroll', () => {
747
+ const authenticatorEnrollments: IdxAuthenticator[] = [
748
+ {
749
+ id: 'enrolled-email-1',
750
+ type: 'email',
751
+ key: AUTHENTICATOR_KEY.EMAIL,
752
+ methods: [{ type: 'email' }],
753
+ displayName: 'Enrolled email',
754
+ },
755
+ ];
756
+ const options: IdxOption[] = [
757
+ {
758
+ label: 'Password',
759
+ value: [
760
+ { name: 'methodType', value: 'password' },
761
+ { name: 'id', value: '1234abc' },
762
+ ],
763
+ relatesTo: {
764
+ id: '',
765
+ type: 'password',
766
+ methods: [{ type: 'password' }],
767
+ displayName: 'Okta Password',
768
+ key: AUTHENTICATOR_KEY.PASSWORD,
769
+ },
770
+ },
771
+ {
772
+ label: 'Email',
773
+ value: [
774
+ { name: 'methodType', value: 'email' },
775
+ { name: 'id', value: '1235abc' },
776
+ ],
777
+ relatesTo: {
778
+ id: '',
779
+ type: 'email',
780
+ methods: [{ type: 'email' }],
781
+ displayName: 'Okta Email',
782
+ key: AUTHENTICATOR_KEY.EMAIL,
783
+ },
784
+ },
785
+ ];
786
+
787
+ const authenticatorOptionValues = getAuthenticatorEnrollButtonElements(
788
+ options, stepName, authenticatorEnrollments,
789
+ );
790
+
791
+ expect(authenticatorOptionValues).toMatchSnapshot();
792
+ expect(authenticatorOptionValues.length).toBe(2);
793
+ expect(authenticatorOptionValues[0].options.key).toBe(AUTHENTICATOR_KEY.PASSWORD);
794
+ expect(authenticatorOptionValues[0].label).toBe('Password');
795
+ expect(authenticatorOptionValues[0].options.ctaLabel).toBe('oie.enroll.authenticator.button.text');
796
+ expect(authenticatorOptionValues[1].options.key).toBe(AUTHENTICATOR_KEY.EMAIL);
797
+ expect(authenticatorOptionValues[1].label).toBe('Email');
798
+ expect(authenticatorOptionValues[1].options.ctaLabel).toBe('enroll.choices.setup.another');
799
+ });
722
800
  });
723
801
  });
@@ -10,7 +10,7 @@
10
10
  * See the License for the specific language governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- import { Input } from '@okta/okta-auth-js';
13
+ import { IdxAuthenticator, Input } from '@okta/okta-auth-js';
14
14
  import { IdxOption } from '@okta/okta-auth-js/types/lib/idx/types/idx-js';
15
15
 
16
16
  import {
@@ -93,6 +93,11 @@ export const getOptionValue = (
93
93
  ({ name }) => name === key,
94
94
  );
95
95
 
96
+ const isAuthenticatorAlreadyEnrolled = (
97
+ authenticator: IdxAuthenticator,
98
+ authenticatorEnrollments?: IdxAuthenticator[],
99
+ ) => !!authenticatorEnrollments?.some(({ key }) => key === authenticator.key);
100
+
96
101
  const getAuthenticatorDataSeVal = (authenticatorKey: string, methodType?: string): string => {
97
102
  if (authenticatorKey) {
98
103
  const method = methodType ? `-${methodType}` : '';
@@ -131,49 +136,18 @@ const reorderAuthenticatorButtons = (
131
136
  return updatedAuthenticatorBtns;
132
137
  };
133
138
 
134
- const buildOktaVerifyOptions = (
135
- options: IdxOption[],
136
- step: string,
137
- isEnroll?: boolean,
138
- ): AuthenticatorButtonElement[] => {
139
- const ovRemediation = options.find((option) => option.relatesTo?.key === AUTHENTICATOR_KEY.OV);
140
- const id = (ovRemediation?.value as Input[])?.find(({ name }) => name === 'id')?.value;
141
- const methodType = (ovRemediation?.value as Input[])?.find(({ name }) => name === 'methodType');
142
- if (!methodType?.options?.length) {
143
- return [];
139
+ const getAuthenticatorLabel = (
140
+ option: IdxOption,
141
+ authenticatorKey: string,
142
+ ): string => {
143
+ switch (authenticatorKey) {
144
+ case AUTHENTICATOR_KEY.CUSTOM_APP:
145
+ return option.relatesTo?.displayName ?? option.label;
146
+ case AUTHENTICATOR_KEY.OV:
147
+ return loc('oie.okta_verify.label', 'login');
148
+ default:
149
+ return option.label;
144
150
  }
145
-
146
- return methodType.options.map((option: IdxOption, index: number) => {
147
- const authenticatorButton: AuthenticatorButtonElement = {
148
- type: 'AuthenticatorButton',
149
- label: option.label,
150
- id: `auth_btn_${AUTHENTICATOR_KEY.OV}_${option.value || id}`,
151
- options: {
152
- type: ButtonType.BUTTON,
153
- key: AUTHENTICATOR_KEY.OV,
154
- ctaLabel: isEnroll
155
- ? loc('oie.enroll.authenticator.button.text', 'login')
156
- : loc('oie.verify.authenticator.button.text', 'login'),
157
- description: isEnroll
158
- ? loc(AUTHENTICATOR_ENROLLMENT_DESCR_KEY_MAP[AUTHENTICATOR_KEY.OV], 'login')
159
- : loc('oie.okta_verify.label', 'login'),
160
- ariaLabel: getAuthenticatorAriaLabel(option, AUTHENTICATOR_KEY.OV, option.value, isEnroll),
161
- actionParams: {
162
- 'authenticator.methodType': option.value,
163
- 'authenticator.id': id,
164
- } as ActionParams,
165
- step,
166
- includeData: true,
167
- includeImmutableData: false,
168
- dataSe: getAuthenticatorDataSeVal(AUTHENTICATOR_KEY.OV, option.value as string),
169
- iconName: option.value === 'totp' ? `oktaVerify_${index}` : `oktaVerifyPush_${index}`,
170
- iconDescr: option.value === 'totp'
171
- ? loc('factor.totpSoft.description', 'login')
172
- : loc('factor.push.description', 'login'),
173
- },
174
- };
175
- return authenticatorButton;
176
- });
177
151
  };
178
152
 
179
153
  const getAuthenticatorDescriptionParams = (
@@ -236,15 +210,76 @@ const getAuthenticatorDescription = (
236
210
  return option.relatesTo?.profile?.phoneNumber as string || undefined;
237
211
  case AUTHENTICATOR_KEY.EMAIL:
238
212
  return option.relatesTo?.profile?.email as string || undefined;
239
- case AUTHENTICATOR_KEY.CUSTOM_APP:
240
- return option.relatesTo?.displayName as string || undefined;
241
213
  case AUTHENTICATOR_KEY.OV:
242
- return loc('oie.okta_verify.label', 'login');
214
+ return option.label;
243
215
  default:
244
216
  return undefined;
245
217
  }
246
218
  };
247
219
 
220
+ const getCtaLabel = (
221
+ isEnroll?: boolean,
222
+ isAdditionalEnroll?: boolean,
223
+ ) => {
224
+ if (isAdditionalEnroll) {
225
+ return loc('enroll.choices.setup.another', 'login');
226
+ }
227
+ if (isEnroll) {
228
+ return loc('oie.enroll.authenticator.button.text', 'login');
229
+ }
230
+ return loc('oie.verify.authenticator.button.text', 'login');
231
+ };
232
+
233
+ const buildOktaVerifyOptions = (
234
+ options: IdxOption[],
235
+ step: string,
236
+ isEnroll?: boolean,
237
+ authenticatorEnrollments?: IdxAuthenticator[],
238
+ ): AuthenticatorButtonElement[] => {
239
+ const ovRemediation = options.find((option) => option.relatesTo?.key === AUTHENTICATOR_KEY.OV);
240
+ const isAdditionalEnroll = isEnroll && ovRemediation?.relatesTo
241
+ && isAuthenticatorAlreadyEnrolled(ovRemediation.relatesTo, authenticatorEnrollments);
242
+ const id = (ovRemediation?.value as Input[])?.find(({ name }) => name === 'id')?.value;
243
+ const methodType = (ovRemediation?.value as Input[])?.find(({ name }) => name === 'methodType');
244
+ if (!methodType?.options?.length) {
245
+ return [];
246
+ }
247
+
248
+ return methodType.options.map((option: IdxOption, index: number) => {
249
+ const authenticatorButton: AuthenticatorButtonElement = {
250
+ type: 'AuthenticatorButton',
251
+ label: getAuthenticatorLabel(option, AUTHENTICATOR_KEY.OV),
252
+ id: `auth_btn_${AUTHENTICATOR_KEY.OV}_${option.value || id}`,
253
+ options: {
254
+ type: ButtonType.BUTTON,
255
+ key: AUTHENTICATOR_KEY.OV,
256
+ isEnroll,
257
+ isAdditionalEnroll,
258
+ ctaLabel: getCtaLabel(isEnroll, isAdditionalEnroll),
259
+ description: getAuthenticatorDescription(
260
+ option,
261
+ AUTHENTICATOR_KEY.OV,
262
+ isEnroll,
263
+ ),
264
+ ariaLabel: getAuthenticatorAriaLabel(option, AUTHENTICATOR_KEY.OV, option.value, isEnroll),
265
+ actionParams: {
266
+ 'authenticator.methodType': option.value,
267
+ 'authenticator.id': id,
268
+ } as ActionParams,
269
+ step,
270
+ includeData: true,
271
+ includeImmutableData: false,
272
+ dataSe: getAuthenticatorDataSeVal(AUTHENTICATOR_KEY.OV, option.value as string),
273
+ iconName: option.value === 'totp' ? `oktaVerify_${index}` : `oktaVerifyPush_${index}`,
274
+ iconDescr: option.value === 'totp'
275
+ ? loc('factor.totpSoft.description', 'login')
276
+ : loc('factor.push.description', 'login'),
277
+ },
278
+ };
279
+ return authenticatorButton;
280
+ });
281
+ };
282
+
248
283
  const getNickname = (
249
284
  option: IdxOption,
250
285
  authenticatorKey: string,
@@ -280,6 +315,7 @@ const formatAuthenticatorOptions = (
280
315
  options: IdxOption[],
281
316
  step: string,
282
317
  isEnroll?: boolean,
318
+ authenticatorEnrollments?: IdxAuthenticator[],
283
319
  ): AuthenticatorButtonElement[] => {
284
320
  const authenticatorOptionSet = new Set<string>();
285
321
  return options
@@ -304,10 +340,13 @@ const formatAuthenticatorOptions = (
304
340
  return !isDup;
305
341
  })
306
342
  .map((option: IdxOption, index: number) => {
307
- const authenticatorKey = option.relatesTo?.key as string;
343
+ const authenticator = option.relatesTo;
344
+ const authenticatorKey = authenticator?.key as string;
308
345
  const id = getOptionValue(option.value as Input[], 'id')?.value;
309
346
  const methodType = getOptionValue(option.value as Input[], 'methodType')?.value;
310
347
  const enrollmentId = getOptionValue(option.value as Input[], 'enrollmentId')?.value;
348
+ const isAdditionalEnroll = isEnroll && authenticator
349
+ && isAuthenticatorAlreadyEnrolled(authenticator, authenticatorEnrollments);
311
350
  const AUTHENTICATORS_WITH_METHOD_TYPE = [
312
351
  AUTHENTICATOR_KEY.ON_PREM,
313
352
  AUTHENTICATOR_KEY.OV,
@@ -315,26 +354,25 @@ const formatAuthenticatorOptions = (
315
354
  ];
316
355
  const AUTHENTICATORS_WITH_NO_TRANSLATE_CLASS = [
317
356
  AUTHENTICATOR_KEY.PHONE,
318
- AUTHENTICATOR_KEY.CUSTOM_APP,
357
+ AUTHENTICATOR_KEY.EMAIL,
319
358
  ];
320
359
  const AUTHENTICATORS_WITH_LTR_DESCRIPTION = [
321
360
  AUTHENTICATOR_KEY.PHONE,
322
361
  ];
323
- const authenticator = option.relatesTo;
324
362
 
325
363
  return {
326
364
  type: 'AuthenticatorButton',
327
- label: option.label,
365
+ label: getAuthenticatorLabel(option, authenticatorKey),
328
366
  id: `auth_btn_${authenticatorKey}_${enrollmentId || id}`,
329
367
  noTranslate: !isEnroll && AUTHENTICATORS_WITH_NO_TRANSLATE_CLASS.includes(authenticatorKey),
330
368
  dir: !isEnroll && AUTHENTICATORS_WITH_LTR_DESCRIPTION.includes(authenticatorKey) ? 'ltr' : undefined,
331
369
  options: {
332
370
  type: ButtonType.BUTTON,
333
371
  key: authenticatorKey,
372
+ isEnroll,
373
+ isAdditionalEnroll,
334
374
  authenticator,
335
- ctaLabel: isEnroll
336
- ? loc('oie.enroll.authenticator.button.text', 'login')
337
- : loc('oie.verify.authenticator.button.text', 'login'),
375
+ ctaLabel: getCtaLabel(isEnroll, isAdditionalEnroll),
338
376
  description: getAuthenticatorDescription(
339
377
  option,
340
378
  authenticatorKey,
@@ -371,13 +409,18 @@ const getAuthenticatorButtonElements = (
371
409
  options: IdxOption[],
372
410
  step: string,
373
411
  isEnroll?: boolean,
412
+ authenticatorEnrollments?: IdxAuthenticator[],
374
413
  ): AuthenticatorButtonElement[] => {
375
- const formattedOptions = formatAuthenticatorOptions(options, step, isEnroll);
414
+ const formattedOptions = formatAuthenticatorOptions(
415
+ options, step, isEnroll, authenticatorEnrollments,
416
+ );
376
417
 
377
418
  // appending OV options back to its original spot
378
- const ovOptions = buildOktaVerifyOptions(options, step, isEnroll);
419
+ const ovOptions = buildOktaVerifyOptions(options, step, isEnroll, authenticatorEnrollments);
379
420
  if (ovOptions.length && options?.length) {
380
- const ovIndex = options.findIndex(({ relatesTo }) => relatesTo?.key === AUTHENTICATOR_KEY.OV);
421
+ const ovIndex = formattedOptions.findIndex((
422
+ { options: { authenticator } },
423
+ ) => authenticator?.key === AUTHENTICATOR_KEY.OV);
381
424
  formattedOptions.splice(ovIndex, 1, ...ovOptions);
382
425
  }
383
426
 
@@ -405,9 +448,8 @@ export const getAppAuthenticatorMethodButtonElements = (
405
448
 
406
449
  const authButtons = methodType.options.map((option, index) => ({
407
450
  type: 'AuthenticatorButton',
408
- label: option.label,
451
+ label: getAuthenticatorLabel(option, authKey),
409
452
  id: `auth_btn_${authKey}_${option.value as string}`,
410
- noTranslate: authKey === AUTHENTICATOR_KEY.CUSTOM_APP,
411
453
  options: {
412
454
  type: ButtonType.BUTTON,
413
455
  key: authKey,
@@ -458,8 +500,10 @@ export const getAuthenticatorVerifyButtonElements = (
458
500
  export const getAuthenticatorEnrollButtonElements = (
459
501
  authenticatorOptions: IdxOption[],
460
502
  step: string,
503
+ authenticatorEnrollments?: IdxAuthenticator[],
461
504
  ): AuthenticatorButtonElement[] => getAuthenticatorButtonElements(
462
505
  authenticatorOptions,
463
506
  step,
464
507
  true,
508
+ authenticatorEnrollments,
465
509
  );
@@ -14,7 +14,6 @@ import {
14
14
  AppIcon,
15
15
  DeviceIcon,
16
16
  LocationIcon,
17
- MobileDeviceIcon,
18
17
  } from '../../components/Images';
19
18
  import { CHALLENGE_INTENT_TO_I18KEY } from '../../constants';
20
19
  import {
@@ -89,12 +88,11 @@ export const transformEmailMagicLinkOTPOnly: TerminalKeyTransformer = (transacti
89
88
  const clientOs = client?.value?.os;
90
89
  const clientBrowser = client?.value?.browser;
91
90
  if (clientBrowser && clientOs) {
92
- const isMobileDevice = clientOs === 'Android' || clientOs === 'iOS';
93
91
  browserImageElement = {
94
92
  type: 'ImageWithText',
95
93
  options: {
96
94
  id: 'browser',
97
- SVGIcon: isMobileDevice ? MobileDeviceIcon : DeviceIcon,
95
+ SVGIcon: DeviceIcon,
98
96
  textContent: loc(
99
97
  'idx.return.link.otponly.browser.on.os',
100
98
  'login',
@@ -36,9 +36,6 @@ jest.mock('./applyAsteriskToFieldElements', () => ({
36
36
  jest.mock('./updatePasswordDescribedByValue', () => ({
37
37
  updatePasswordDescribedByValue: () => ({}),
38
38
  }));
39
- jest.mock('./setLtrFields', () => ({
40
- setLtrFields: () => ({}),
41
- }));
42
39
  jest.mock('./overwriteAutocomplete', () => ({
43
40
  overwriteAutocomplete: () => () => ({}),
44
41
  }));
@@ -55,7 +52,6 @@ const mocked = {
55
52
  setFocus: require('./setFocusOnFirstElement'),
56
53
  applyAsterisk: require('./applyAsteriskToFieldElements'),
57
54
  updatePasswordEle: require('./updatePasswordDescribedByValue'),
58
- setLtrField: require('./setLtrFields'),
59
55
  overwriteAutocomplete: require('./overwriteAutocomplete'),
60
56
  createIdentifierContainer: require('./createIdentifierContainer'),
61
57
  };
@@ -70,7 +66,6 @@ describe('UISchema transformer', () => {
70
66
  jest.spyOn(mocked.setFocus, 'setFocusOnFirstElement');
71
67
  jest.spyOn(mocked.applyAsterisk, 'applyAsteriskToFieldElements');
72
68
  jest.spyOn(mocked.updatePasswordEle, 'updatePasswordDescribedByValue');
73
- jest.spyOn(mocked.setLtrField, 'setLtrFields');
74
69
  jest.spyOn(mocked.overwriteAutocomplete, 'overwriteAutocomplete');
75
70
  jest.spyOn(mocked.createIdentifierContainer, 'createIdentifierContainer');
76
71
 
@@ -95,7 +90,6 @@ describe('UISchema transformer', () => {
95
90
  expect(mocked.setFocus.setFocusOnFirstElement).toHaveBeenCalled();
96
91
  expect(mocked.applyAsterisk.applyAsteriskToFieldElements).toHaveBeenCalled();
97
92
  expect(mocked.updatePasswordEle.updatePasswordDescribedByValue).toHaveBeenCalled();
98
- expect(mocked.setLtrField.setLtrFields).toHaveBeenCalled();
99
93
  expect(mocked.overwriteAutocomplete.overwriteAutocomplete).toHaveBeenCalled();
100
94
  expect(mocked.createIdentifierContainer.createIdentifierContainer).toHaveBeenCalled();
101
95
  });