@aws-amplify/auth 6.5.0 → 6.5.1-email-mfa-test.4e655bc.0

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 (33) hide show
  1. package/dist/cjs/common/AuthErrorStrings.js +2 -2
  2. package/dist/cjs/common/AuthErrorStrings.js.map +1 -1
  3. package/dist/cjs/providers/cognito/apis/confirmSignIn.js +2 -2
  4. package/dist/cjs/providers/cognito/apis/confirmSignIn.js.map +1 -1
  5. package/dist/cjs/providers/cognito/apis/updateMFAPreference.js +2 -1
  6. package/dist/cjs/providers/cognito/apis/updateMFAPreference.js.map +1 -1
  7. package/dist/cjs/providers/cognito/utils/oauth/getRedirectUrl.js +3 -1
  8. package/dist/cjs/providers/cognito/utils/oauth/getRedirectUrl.js.map +1 -1
  9. package/dist/cjs/providers/cognito/utils/signInHelpers.js +183 -130
  10. package/dist/cjs/providers/cognito/utils/signInHelpers.js.map +1 -1
  11. package/dist/esm/common/AuthErrorStrings.mjs +2 -2
  12. package/dist/esm/common/AuthErrorStrings.mjs.map +1 -1
  13. package/dist/esm/foundation/factories/serviceClients/cognitoIdentityProvider/types/sdk.d.ts +24 -3
  14. package/dist/esm/providers/cognito/apis/confirmSignIn.mjs +2 -2
  15. package/dist/esm/providers/cognito/apis/confirmSignIn.mjs.map +1 -1
  16. package/dist/esm/providers/cognito/apis/updateMFAPreference.mjs +2 -1
  17. package/dist/esm/providers/cognito/apis/updateMFAPreference.mjs.map +1 -1
  18. package/dist/esm/providers/cognito/types/inputs.d.ts +1 -0
  19. package/dist/esm/providers/cognito/utils/oauth/getRedirectUrl.mjs +3 -1
  20. package/dist/esm/providers/cognito/utils/oauth/getRedirectUrl.mjs.map +1 -1
  21. package/dist/esm/providers/cognito/utils/signInHelpers.d.ts +4 -3
  22. package/dist/esm/providers/cognito/utils/signInHelpers.mjs +181 -127
  23. package/dist/esm/providers/cognito/utils/signInHelpers.mjs.map +1 -1
  24. package/dist/esm/types/models.d.ts +44 -2
  25. package/package.json +104 -104
  26. package/src/common/AuthErrorStrings.ts +4 -2
  27. package/src/foundation/factories/serviceClients/cognitoIdentityProvider/types/sdk.ts +23 -1
  28. package/src/providers/cognito/apis/confirmSignIn.ts +2 -2
  29. package/src/providers/cognito/apis/updateMFAPreference.ts +2 -1
  30. package/src/providers/cognito/types/inputs.ts +1 -0
  31. package/src/providers/cognito/utils/oauth/getRedirectUrl.ts +1 -0
  32. package/src/providers/cognito/utils/signInHelpers.ts +240 -166
  33. package/src/types/models.ts +48 -1
@@ -76,43 +76,90 @@ async function handleCustomChallenge({ challengeResponse, clientMetadata, sessio
76
76
  }
77
77
  async function handleMFASetupChallenge({ challengeResponse, username, clientMetadata, session, deviceName, config, }) {
78
78
  const { userPoolId, userPoolClientId, userPoolEndpoint } = config;
79
+ if (challengeResponse === 'EMAIL') {
80
+ return {
81
+ ChallengeName: 'MFA_SETUP',
82
+ Session: session,
83
+ ChallengeParameters: {
84
+ MFAS_CAN_SETUP: '["EMAIL_OTP"]',
85
+ },
86
+ $metadata: {},
87
+ };
88
+ }
89
+ if (challengeResponse === 'TOTP') {
90
+ return {
91
+ ChallengeName: 'MFA_SETUP',
92
+ Session: session,
93
+ ChallengeParameters: {
94
+ MFAS_CAN_SETUP: '["SOFTWARE_TOKEN_MFA"]',
95
+ },
96
+ $metadata: {},
97
+ };
98
+ }
79
99
  const challengeResponses = {
80
100
  USERNAME: username,
81
101
  };
82
- const verifySoftwareToken = createVerifySoftwareTokenClient({
83
- endpointResolver: createCognitoUserPoolEndpointResolver({
84
- endpointOverride: userPoolEndpoint,
85
- }),
86
- });
87
- const { Session } = await verifySoftwareToken({
88
- region: getRegionFromUserPoolId(userPoolId),
89
- userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn),
90
- }, {
91
- UserCode: challengeResponse,
92
- Session: session,
93
- FriendlyDeviceName: deviceName,
94
- });
95
- signInStore.dispatch({
96
- type: 'SET_SIGN_IN_SESSION',
97
- value: Session,
98
- });
99
- const jsonReq = {
100
- ChallengeName: 'MFA_SETUP',
101
- ChallengeResponses: challengeResponses,
102
- Session,
103
- ClientMetadata: clientMetadata,
104
- ClientId: userPoolClientId,
105
- };
106
- const respondToAuthChallenge = createRespondToAuthChallengeClient({
107
- endpointResolver: createCognitoUserPoolEndpointResolver({
108
- endpointOverride: userPoolEndpoint,
109
- }),
102
+ const isTOTPCode = /^\d+$/.test(challengeResponse.trim());
103
+ if (isTOTPCode) {
104
+ const verifySoftwareToken = createVerifySoftwareTokenClient({
105
+ endpointResolver: createCognitoUserPoolEndpointResolver({
106
+ endpointOverride: userPoolEndpoint,
107
+ }),
108
+ });
109
+ const { Session } = await verifySoftwareToken({
110
+ region: getRegionFromUserPoolId(userPoolId),
111
+ userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn),
112
+ }, {
113
+ UserCode: challengeResponse,
114
+ Session: session,
115
+ FriendlyDeviceName: deviceName,
116
+ });
117
+ signInStore.dispatch({
118
+ type: 'SET_SIGN_IN_SESSION',
119
+ value: Session,
120
+ });
121
+ const jsonReq = {
122
+ ChallengeName: 'MFA_SETUP',
123
+ ChallengeResponses: challengeResponses,
124
+ Session,
125
+ ClientMetadata: clientMetadata,
126
+ ClientId: userPoolClientId,
127
+ };
128
+ const respondToAuthChallenge = createRespondToAuthChallengeClient({
129
+ endpointResolver: createCognitoUserPoolEndpointResolver({
130
+ endpointOverride: userPoolEndpoint,
131
+ }),
132
+ });
133
+ return respondToAuthChallenge({ region: getRegionFromUserPoolId(userPoolId) }, jsonReq);
134
+ }
135
+ const isEmail = /^\S+@\S+\.\S+$/.test(challengeResponse.trim());
136
+ if (isEmail) {
137
+ challengeResponses.EMAIL = challengeResponse;
138
+ const jsonReq = {
139
+ ChallengeName: 'MFA_SETUP',
140
+ ChallengeResponses: challengeResponses,
141
+ Session: session,
142
+ ClientMetadata: clientMetadata,
143
+ ClientId: userPoolClientId,
144
+ };
145
+ const respondToAuthChallenge = createRespondToAuthChallengeClient({
146
+ endpointResolver: createCognitoUserPoolEndpointResolver({
147
+ endpointOverride: userPoolEndpoint,
148
+ }),
149
+ });
150
+ return respondToAuthChallenge({ region: getRegionFromUserPoolId(userPoolId) }, jsonReq);
151
+ }
152
+ throw new AuthError({
153
+ name: AuthErrorCodes.SignInException,
154
+ message: `Cannot proceed with MFA setup using challengeResponse: ${challengeResponse}`,
155
+ recoverySuggestion: 'Try passing "EMAIL", "TOTP", a valid email, or OTP code as the challengeResponse.',
110
156
  });
111
- return respondToAuthChallenge({ region: getRegionFromUserPoolId(userPoolId) }, jsonReq);
112
157
  }
113
158
  async function handleSelectMFATypeChallenge({ challengeResponse, username, clientMetadata, session, config, }) {
114
159
  const { userPoolId, userPoolClientId, userPoolEndpoint } = config;
115
- assertValidationError(challengeResponse === 'TOTP' || challengeResponse === 'SMS', AuthValidationErrorCode.IncorrectMFAMethod);
160
+ assertValidationError(challengeResponse === 'TOTP' ||
161
+ challengeResponse === 'SMS' ||
162
+ challengeResponse === 'EMAIL', AuthValidationErrorCode.IncorrectMFAMethod);
116
163
  const challengeResponses = {
117
164
  USERNAME: username,
118
165
  ANSWER: mapMfaType(challengeResponse),
@@ -140,64 +187,6 @@ async function handleSelectMFATypeChallenge({ challengeResponse, username, clien
140
187
  userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn),
141
188
  }, jsonReq);
142
189
  }
143
- async function handleSMSMFAChallenge({ challengeResponse, clientMetadata, session, username, config, }) {
144
- const { userPoolId, userPoolClientId, userPoolEndpoint } = config;
145
- const challengeResponses = {
146
- USERNAME: username,
147
- SMS_MFA_CODE: challengeResponse,
148
- };
149
- const UserContextData = getUserContextData({
150
- username,
151
- userPoolId,
152
- userPoolClientId,
153
- });
154
- const jsonReq = {
155
- ChallengeName: 'SMS_MFA',
156
- ChallengeResponses: challengeResponses,
157
- Session: session,
158
- ClientMetadata: clientMetadata,
159
- ClientId: userPoolClientId,
160
- UserContextData,
161
- };
162
- const respondToAuthChallenge = createRespondToAuthChallengeClient({
163
- endpointResolver: createCognitoUserPoolEndpointResolver({
164
- endpointOverride: userPoolEndpoint,
165
- }),
166
- });
167
- return respondToAuthChallenge({
168
- region: getRegionFromUserPoolId(userPoolId),
169
- userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn),
170
- }, jsonReq);
171
- }
172
- async function handleSoftwareTokenMFAChallenge({ challengeResponse, clientMetadata, session, username, config, }) {
173
- const { userPoolId, userPoolClientId, userPoolEndpoint } = config;
174
- const challengeResponses = {
175
- USERNAME: username,
176
- SOFTWARE_TOKEN_MFA_CODE: challengeResponse,
177
- };
178
- const UserContextData = getUserContextData({
179
- username,
180
- userPoolId,
181
- userPoolClientId,
182
- });
183
- const jsonReq = {
184
- ChallengeName: 'SOFTWARE_TOKEN_MFA',
185
- ChallengeResponses: challengeResponses,
186
- Session: session,
187
- ClientMetadata: clientMetadata,
188
- ClientId: userPoolClientId,
189
- UserContextData,
190
- };
191
- const respondToAuthChallenge = createRespondToAuthChallengeClient({
192
- endpointResolver: createCognitoUserPoolEndpointResolver({
193
- endpointOverride: userPoolEndpoint,
194
- }),
195
- });
196
- return respondToAuthChallenge({
197
- region: getRegionFromUserPoolId(userPoolId),
198
- userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn),
199
- }, jsonReq);
200
- }
201
190
  async function handleCompleteNewPasswordChallenge({ challengeResponse, clientMetadata, session, username, requiredAttributes, config, }) {
202
191
  const { userPoolId, userPoolClientId, userPoolEndpoint } = config;
203
192
  const challengeResponses = {
@@ -551,30 +540,52 @@ async function getSignInResult(params) {
551
540
  };
552
541
  case 'MFA_SETUP': {
553
542
  const { signInSession, username } = signInStore.getState();
554
- if (!isMFATypeEnabled(challengeParameters, 'TOTP'))
555
- throw new AuthError({
556
- name: AuthErrorCodes.SignInException,
557
- message: `Cannot initiate MFA setup from available types: ${getMFATypes(parseMFATypes(challengeParameters.MFAS_CAN_SETUP))}`,
543
+ const mfaSetupTypes = getMFATypes(parseMFATypes(challengeParameters.MFAS_CAN_SETUP)) || [];
544
+ const allowedMfaSetupTypes = getAllowedMfaSetupTypes(mfaSetupTypes);
545
+ const isTotpMfaSetupAvailable = allowedMfaSetupTypes.includes('TOTP');
546
+ const isEmailMfaSetupAvailable = allowedMfaSetupTypes.includes('EMAIL');
547
+ if (isTotpMfaSetupAvailable && isEmailMfaSetupAvailable) {
548
+ return {
549
+ isSignedIn: false,
550
+ nextStep: {
551
+ signInStep: 'CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION',
552
+ allowedMFATypes: allowedMfaSetupTypes,
553
+ },
554
+ };
555
+ }
556
+ if (isEmailMfaSetupAvailable) {
557
+ return {
558
+ isSignedIn: false,
559
+ nextStep: {
560
+ signInStep: 'CONTINUE_SIGN_IN_WITH_EMAIL_SETUP',
561
+ },
562
+ };
563
+ }
564
+ if (isTotpMfaSetupAvailable) {
565
+ const associateSoftwareToken = createAssociateSoftwareTokenClient({
566
+ endpointResolver: createCognitoUserPoolEndpointResolver({
567
+ endpointOverride: authConfig.userPoolEndpoint,
568
+ }),
558
569
  });
559
- const associateSoftwareToken = createAssociateSoftwareTokenClient({
560
- endpointResolver: createCognitoUserPoolEndpointResolver({
561
- endpointOverride: authConfig.userPoolEndpoint,
562
- }),
563
- });
564
- const { Session, SecretCode: secretCode } = await associateSoftwareToken({ region: getRegionFromUserPoolId(authConfig.userPoolId) }, {
565
- Session: signInSession,
566
- });
567
- signInStore.dispatch({
568
- type: 'SET_SIGN_IN_SESSION',
569
- value: Session,
570
+ const { Session, SecretCode: secretCode } = await associateSoftwareToken({ region: getRegionFromUserPoolId(authConfig.userPoolId) }, {
571
+ Session: signInSession,
572
+ });
573
+ signInStore.dispatch({
574
+ type: 'SET_SIGN_IN_SESSION',
575
+ value: Session,
576
+ });
577
+ return {
578
+ isSignedIn: false,
579
+ nextStep: {
580
+ signInStep: 'CONTINUE_SIGN_IN_WITH_TOTP_SETUP',
581
+ totpSetupDetails: getTOTPSetupDetails(secretCode, username),
582
+ },
583
+ };
584
+ }
585
+ throw new AuthError({
586
+ name: AuthErrorCodes.SignInException,
587
+ message: `Cannot initiate MFA setup from available types: ${mfaSetupTypes}`,
570
588
  });
571
- return {
572
- isSignedIn: false,
573
- nextStep: {
574
- signInStep: 'CONTINUE_SIGN_IN_WITH_TOTP_SETUP',
575
- totpSetupDetails: getTOTPSetupDetails(secretCode, username),
576
- },
577
- };
578
589
  }
579
590
  case 'NEW_PASSWORD_REQUIRED':
580
591
  return {
@@ -610,6 +621,17 @@ async function getSignInResult(params) {
610
621
  signInStep: 'CONFIRM_SIGN_IN_WITH_TOTP_CODE',
611
622
  },
612
623
  };
624
+ case 'EMAIL_OTP':
625
+ return {
626
+ isSignedIn: false,
627
+ nextStep: {
628
+ signInStep: 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE',
629
+ codeDeliveryDetails: {
630
+ deliveryMedium: challengeParameters.CODE_DELIVERY_DELIVERY_MEDIUM,
631
+ destination: challengeParameters.CODE_DELIVERY_DESTINATION,
632
+ },
633
+ },
634
+ };
613
635
  }
614
636
  // TODO: remove this error message for production apps
615
637
  throw new AuthError({
@@ -661,14 +683,6 @@ async function handleChallengeName(username, challengeName, session, challengeRe
661
683
  const userAttributes = options?.userAttributes;
662
684
  const deviceName = options?.friendlyDeviceName;
663
685
  switch (challengeName) {
664
- case 'SMS_MFA':
665
- return handleSMSMFAChallenge({
666
- challengeResponse,
667
- clientMetadata,
668
- session,
669
- username,
670
- config,
671
- });
672
686
  case 'SELECT_MFA_TYPE':
673
687
  return handleSelectMFATypeChallenge({
674
688
  challengeResponse,
@@ -706,8 +720,11 @@ async function handleChallengeName(username, challengeName, session, challengeRe
706
720
  tokenOrchestrator,
707
721
  },
708
722
  ], username, tokenOrchestrator);
723
+ case 'SMS_MFA':
709
724
  case 'SOFTWARE_TOKEN_MFA':
710
- return handleSoftwareTokenMFAChallenge({
725
+ case 'EMAIL_OTP':
726
+ return handleMFAChallenge({
727
+ challengeName,
711
728
  challengeResponse,
712
729
  clientMetadata,
713
730
  session,
@@ -718,7 +735,7 @@ async function handleChallengeName(username, challengeName, session, challengeRe
718
735
  // TODO: remove this error message for production apps
719
736
  throw new AuthError({
720
737
  name: AuthErrorCodes.SignInException,
721
- message: `An error occurred during the sign in process.
738
+ message: `An error occurred during the sign in process.
722
739
  ${challengeName} challengeName returned by the underlying service was not addressed.`,
723
740
  });
724
741
  }
@@ -726,6 +743,8 @@ function mapMfaType(mfa) {
726
743
  let mfaType = 'SMS_MFA';
727
744
  if (mfa === 'TOTP')
728
745
  mfaType = 'SOFTWARE_TOKEN_MFA';
746
+ if (mfa === 'EMAIL')
747
+ mfaType = 'EMAIL_OTP';
729
748
  return mfaType;
730
749
  }
731
750
  function getMFAType(type) {
@@ -733,6 +752,8 @@ function getMFAType(type) {
733
752
  return 'SMS';
734
753
  if (type === 'SOFTWARE_TOKEN_MFA')
735
754
  return 'TOTP';
755
+ if (type === 'EMAIL_OTP')
756
+ return 'EMAIL';
736
757
  // TODO: log warning for unknown MFA type
737
758
  }
738
759
  function getMFATypes(types) {
@@ -745,12 +766,8 @@ function parseMFATypes(mfa) {
745
766
  return [];
746
767
  return JSON.parse(mfa);
747
768
  }
748
- function isMFATypeEnabled(challengeParams, mfaType) {
749
- const { MFAS_CAN_SETUP } = challengeParams;
750
- const mfaTypes = getMFATypes(parseMFATypes(MFAS_CAN_SETUP));
751
- if (!mfaTypes)
752
- return false;
753
- return mfaTypes.includes(mfaType);
769
+ function getAllowedMfaSetupTypes(availableMfaSetupTypes) {
770
+ return availableMfaSetupTypes.filter(authMfaType => authMfaType === 'EMAIL' || authMfaType === 'TOTP');
754
771
  }
755
772
  async function assertUserNotAuthenticated() {
756
773
  let authUser;
@@ -844,6 +861,43 @@ function getActiveSignInUsername(username) {
844
861
  const state = signInStore.getState();
845
862
  return state.username ?? username;
846
863
  }
864
+ async function handleMFAChallenge({ challengeName, challengeResponse, clientMetadata, session, username, config, }) {
865
+ const { userPoolId, userPoolClientId, userPoolEndpoint } = config;
866
+ const challengeResponses = {
867
+ USERNAME: username,
868
+ };
869
+ if (challengeName === 'EMAIL_OTP') {
870
+ challengeResponses.EMAIL_OTP_CODE = challengeResponse;
871
+ }
872
+ if (challengeName === 'SMS_MFA') {
873
+ challengeResponses.SMS_MFA_CODE = challengeResponse;
874
+ }
875
+ if (challengeName === 'SOFTWARE_TOKEN_MFA') {
876
+ challengeResponses.SOFTWARE_TOKEN_MFA_CODE = challengeResponse;
877
+ }
878
+ const userContextData = getUserContextData({
879
+ username,
880
+ userPoolId,
881
+ userPoolClientId,
882
+ });
883
+ const jsonReq = {
884
+ ChallengeName: challengeName,
885
+ ChallengeResponses: challengeResponses,
886
+ Session: session,
887
+ ClientMetadata: clientMetadata,
888
+ ClientId: userPoolClientId,
889
+ UserContextData: userContextData,
890
+ };
891
+ const respondToAuthChallenge = createRespondToAuthChallengeClient({
892
+ endpointResolver: createCognitoUserPoolEndpointResolver({
893
+ endpointOverride: userPoolEndpoint,
894
+ }),
895
+ });
896
+ return respondToAuthChallenge({
897
+ region: getRegionFromUserPoolId(userPoolId),
898
+ userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn),
899
+ }, jsonReq);
900
+ }
847
901
 
848
- export { assertUserNotAuthenticated, createAttributes, getActiveSignInUsername, getMFAType, getMFATypes, getNewDeviceMetadata, getSignInResult, getSignInResultFromError, getTOTPSetupDetails, handleChallengeName, handleCompleteNewPasswordChallenge, handleCustomAuthFlowWithoutSRP, handleCustomChallenge, handleCustomSRPAuthFlow, handleMFASetupChallenge, handlePasswordVerifierChallenge, handleSMSMFAChallenge, handleSelectMFATypeChallenge, handleSoftwareTokenMFAChallenge, handleUserPasswordAuthFlow, handleUserSRPAuthFlow, isMFATypeEnabled, mapMfaType, parseAttributes, parseMFATypes, retryOnResourceNotFoundException, setActiveSignInUsername };
902
+ export { assertUserNotAuthenticated, createAttributes, getActiveSignInUsername, getAllowedMfaSetupTypes, getMFAType, getMFATypes, getNewDeviceMetadata, getSignInResult, getSignInResultFromError, getTOTPSetupDetails, handleChallengeName, handleCompleteNewPasswordChallenge, handleCustomAuthFlowWithoutSRP, handleCustomChallenge, handleCustomSRPAuthFlow, handleMFAChallenge, handleMFASetupChallenge, handlePasswordVerifierChallenge, handleSelectMFATypeChallenge, handleUserPasswordAuthFlow, handleUserSRPAuthFlow, mapMfaType, parseAttributes, parseMFATypes, retryOnResourceNotFoundException, setActiveSignInUsername };
849
903
  //# sourceMappingURL=signInHelpers.mjs.map