@aws-amplify/auth 6.5.5 → 6.5.6-unstable.42db720.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.
- package/dist/cjs/common/AuthErrorStrings.js +2 -2
- package/dist/cjs/common/AuthErrorStrings.js.map +1 -1
- package/dist/cjs/providers/cognito/apis/confirmSignIn.js +2 -2
- package/dist/cjs/providers/cognito/apis/confirmSignIn.js.map +1 -1
- package/dist/cjs/providers/cognito/apis/updateMFAPreference.js +2 -1
- package/dist/cjs/providers/cognito/apis/updateMFAPreference.js.map +1 -1
- package/dist/cjs/providers/cognito/utils/signInHelpers.js +189 -130
- package/dist/cjs/providers/cognito/utils/signInHelpers.js.map +1 -1
- package/dist/esm/common/AuthErrorStrings.mjs +2 -2
- package/dist/esm/common/AuthErrorStrings.mjs.map +1 -1
- package/dist/esm/foundation/factories/serviceClients/cognitoIdentityProvider/types/sdk.d.ts +24 -3
- package/dist/esm/providers/cognito/apis/confirmSignIn.mjs +2 -2
- package/dist/esm/providers/cognito/apis/confirmSignIn.mjs.map +1 -1
- package/dist/esm/providers/cognito/apis/updateMFAPreference.mjs +2 -1
- package/dist/esm/providers/cognito/apis/updateMFAPreference.mjs.map +1 -1
- package/dist/esm/providers/cognito/types/inputs.d.ts +1 -0
- package/dist/esm/providers/cognito/utils/signInHelpers.d.ts +4 -3
- package/dist/esm/providers/cognito/utils/signInHelpers.mjs +187 -127
- package/dist/esm/providers/cognito/utils/signInHelpers.mjs.map +1 -1
- package/dist/esm/types/models.d.ts +44 -2
- package/package.json +104 -104
- package/src/common/AuthErrorStrings.ts +4 -2
- package/src/foundation/factories/serviceClients/cognitoIdentityProvider/types/sdk.ts +23 -1
- package/src/providers/cognito/apis/confirmSignIn.ts +2 -2
- package/src/providers/cognito/apis/updateMFAPreference.ts +2 -1
- package/src/providers/cognito/types/inputs.ts +1 -0
- package/src/providers/cognito/utils/signInHelpers.ts +246 -166
- package/src/types/models.ts +48 -1
|
@@ -8,6 +8,7 @@ import { MetadataBearer as __MetadataBearer } from '@aws-sdk/types';
|
|
|
8
8
|
export type ChallengeName =
|
|
9
9
|
| 'SMS_MFA'
|
|
10
10
|
| 'SOFTWARE_TOKEN_MFA'
|
|
11
|
+
| 'EMAIL_OTP'
|
|
11
12
|
| 'SELECT_MFA_TYPE'
|
|
12
13
|
| 'MFA_SETUP'
|
|
13
14
|
| 'PASSWORD_VERIFIER'
|
|
@@ -28,7 +29,7 @@ export type ChallengeParameters = {
|
|
|
28
29
|
MFAS_CAN_SETUP?: string;
|
|
29
30
|
} & Record<string, unknown>;
|
|
30
31
|
|
|
31
|
-
export type CognitoMFAType = 'SMS_MFA' | 'SOFTWARE_TOKEN_MFA';
|
|
32
|
+
export type CognitoMFAType = 'SMS_MFA' | 'SOFTWARE_TOKEN_MFA' | 'EMAIL_OTP';
|
|
32
33
|
|
|
33
34
|
export interface CognitoMFASettings {
|
|
34
35
|
Enabled?: boolean;
|
|
@@ -55,6 +56,7 @@ declare enum ChallengeNameType {
|
|
|
55
56
|
SELECT_MFA_TYPE = 'SELECT_MFA_TYPE',
|
|
56
57
|
SMS_MFA = 'SMS_MFA',
|
|
57
58
|
SOFTWARE_TOKEN_MFA = 'SOFTWARE_TOKEN_MFA',
|
|
59
|
+
EMAIL_OTP = 'EMAIL_OTP',
|
|
58
60
|
}
|
|
59
61
|
declare enum DeliveryMediumType {
|
|
60
62
|
EMAIL = 'EMAIL',
|
|
@@ -1430,6 +1432,10 @@ export interface SetUserMFAPreferenceRequest {
|
|
|
1430
1432
|
* <p>The time-based one-time password software token MFA settings.</p>
|
|
1431
1433
|
*/
|
|
1432
1434
|
SoftwareTokenMfaSettings?: SoftwareTokenMfaSettingsType;
|
|
1435
|
+
/**
|
|
1436
|
+
* <p>The email message multi-factor authentication (MFA) settings.</p>
|
|
1437
|
+
*/
|
|
1438
|
+
EmailMfaSettings?: EmailMfaSettingsType;
|
|
1433
1439
|
/**
|
|
1434
1440
|
* <p>The access token for the user.</p>
|
|
1435
1441
|
*/
|
|
@@ -1538,6 +1544,22 @@ export interface SoftwareTokenMfaSettingsType {
|
|
|
1538
1544
|
*/
|
|
1539
1545
|
PreferredMfa?: boolean;
|
|
1540
1546
|
}
|
|
1547
|
+
/**
|
|
1548
|
+
* <p>The type used for enabling email MFA at the user level. If an MFA type is activated for a user, the user will be prompted for MFA during all sign-in attempts, unless device tracking
|
|
1549
|
+
* is turned on and the device has been trusted. If you want MFA to be applied selectively based on the assessed risk level of sign-in attempts, deactivate MFA for users and turn on Adaptive
|
|
1550
|
+
* Authentication for the user pool.</p>
|
|
1551
|
+
*/
|
|
1552
|
+
export interface EmailMfaSettingsType {
|
|
1553
|
+
/**
|
|
1554
|
+
* <p>Specifies whether email MFA is activated. If an MFA type is activated for a user, the user will be prompted for MFA during all sign-in attempts, unless device tracking is turned
|
|
1555
|
+
* on and the device has been trusted.</p>
|
|
1556
|
+
*/
|
|
1557
|
+
Enabled?: boolean;
|
|
1558
|
+
/**
|
|
1559
|
+
* <p>Specifies whether email MFA is the preferred MFA method.</p>
|
|
1560
|
+
*/
|
|
1561
|
+
PreferredMfa?: boolean;
|
|
1562
|
+
}
|
|
1541
1563
|
export type UpdateDeviceStatusCommandInput = UpdateDeviceStatusRequest;
|
|
1542
1564
|
export interface UpdateDeviceStatusCommandOutput
|
|
1543
1565
|
extends UpdateDeviceStatusResponse,
|
|
@@ -71,8 +71,8 @@ export async function confirmSignIn(
|
|
|
71
71
|
throw new AuthError({
|
|
72
72
|
name: AuthErrorCodes.SignInException,
|
|
73
73
|
message: `
|
|
74
|
-
An error occurred during the sign in process.
|
|
75
|
-
|
|
74
|
+
An error occurred during the sign in process.
|
|
75
|
+
|
|
76
76
|
This most likely occurred due to:
|
|
77
77
|
1. signIn was not called before confirmSignIn.
|
|
78
78
|
2. signIn threw an exception.
|
|
@@ -27,7 +27,7 @@ import { createCognitoUserPoolEndpointResolver } from '../factories';
|
|
|
27
27
|
export async function updateMFAPreference(
|
|
28
28
|
input: UpdateMFAPreferenceInput,
|
|
29
29
|
): Promise<void> {
|
|
30
|
-
const { sms, totp } = input;
|
|
30
|
+
const { sms, totp, email } = input;
|
|
31
31
|
const authConfig = Amplify.getConfig().Auth?.Cognito;
|
|
32
32
|
assertTokenProviderConfig(authConfig);
|
|
33
33
|
const { userPoolEndpoint, userPoolId } = authConfig;
|
|
@@ -47,6 +47,7 @@ export async function updateMFAPreference(
|
|
|
47
47
|
AccessToken: tokens.accessToken.toString(),
|
|
48
48
|
SMSMfaSettings: getMFASettings(sms),
|
|
49
49
|
SoftwareTokenMfaSettings: getMFASettings(totp),
|
|
50
|
+
EmailMfaSettings: getMFASettings(email),
|
|
50
51
|
},
|
|
51
52
|
);
|
|
52
53
|
}
|
|
@@ -154,49 +154,116 @@ export async function handleMFASetupChallenge({
|
|
|
154
154
|
config,
|
|
155
155
|
}: HandleAuthChallengeRequest): Promise<RespondToAuthChallengeCommandOutput> {
|
|
156
156
|
const { userPoolId, userPoolClientId, userPoolEndpoint } = config;
|
|
157
|
-
|
|
157
|
+
|
|
158
|
+
if (challengeResponse === 'EMAIL') {
|
|
159
|
+
return {
|
|
160
|
+
ChallengeName: 'MFA_SETUP',
|
|
161
|
+
Session: session,
|
|
162
|
+
ChallengeParameters: {
|
|
163
|
+
MFAS_CAN_SETUP: '["EMAIL_OTP"]',
|
|
164
|
+
},
|
|
165
|
+
$metadata: {},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (challengeResponse === 'TOTP') {
|
|
170
|
+
return {
|
|
171
|
+
ChallengeName: 'MFA_SETUP',
|
|
172
|
+
Session: session,
|
|
173
|
+
ChallengeParameters: {
|
|
174
|
+
MFAS_CAN_SETUP: '["SOFTWARE_TOKEN_MFA"]',
|
|
175
|
+
},
|
|
176
|
+
$metadata: {},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const challengeResponses: Record<string, string> = {
|
|
158
181
|
USERNAME: username,
|
|
159
182
|
};
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
{
|
|
171
|
-
|
|
183
|
+
|
|
184
|
+
const isTOTPCode = /^\d+$/.test(challengeResponse);
|
|
185
|
+
|
|
186
|
+
if (isTOTPCode) {
|
|
187
|
+
const verifySoftwareToken = createVerifySoftwareTokenClient({
|
|
188
|
+
endpointResolver: createCognitoUserPoolEndpointResolver({
|
|
189
|
+
endpointOverride: userPoolEndpoint,
|
|
190
|
+
}),
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const { Session } = await verifySoftwareToken(
|
|
194
|
+
{
|
|
195
|
+
region: getRegionFromUserPoolId(userPoolId),
|
|
196
|
+
userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn),
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
UserCode: challengeResponse,
|
|
200
|
+
Session: session,
|
|
201
|
+
FriendlyDeviceName: deviceName,
|
|
202
|
+
},
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
signInStore.dispatch({
|
|
206
|
+
type: 'SET_SIGN_IN_SESSION',
|
|
207
|
+
value: Session,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const jsonReq: RespondToAuthChallengeCommandInput = {
|
|
211
|
+
ChallengeName: 'MFA_SETUP',
|
|
212
|
+
ChallengeResponses: challengeResponses,
|
|
213
|
+
Session,
|
|
214
|
+
ClientMetadata: clientMetadata,
|
|
215
|
+
ClientId: userPoolClientId,
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const respondToAuthChallenge = createRespondToAuthChallengeClient({
|
|
219
|
+
endpointResolver: createCognitoUserPoolEndpointResolver({
|
|
220
|
+
endpointOverride: userPoolEndpoint,
|
|
221
|
+
}),
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
return respondToAuthChallenge(
|
|
225
|
+
{
|
|
226
|
+
region: getRegionFromUserPoolId(userPoolId),
|
|
227
|
+
userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn),
|
|
228
|
+
},
|
|
229
|
+
jsonReq,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const isEmail = challengeResponse.includes('@');
|
|
234
|
+
|
|
235
|
+
if (isEmail) {
|
|
236
|
+
challengeResponses.EMAIL = challengeResponse;
|
|
237
|
+
|
|
238
|
+
const jsonReq: RespondToAuthChallengeCommandInput = {
|
|
239
|
+
ChallengeName: 'MFA_SETUP',
|
|
240
|
+
ChallengeResponses: challengeResponses,
|
|
172
241
|
Session: session,
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
242
|
+
ClientMetadata: clientMetadata,
|
|
243
|
+
ClientId: userPoolClientId,
|
|
244
|
+
};
|
|
176
245
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
246
|
+
const respondToAuthChallenge = createRespondToAuthChallengeClient({
|
|
247
|
+
endpointResolver: createCognitoUserPoolEndpointResolver({
|
|
248
|
+
endpointOverride: userPoolEndpoint,
|
|
249
|
+
}),
|
|
250
|
+
});
|
|
181
251
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
252
|
+
return respondToAuthChallenge(
|
|
253
|
+
{
|
|
254
|
+
region: getRegionFromUserPoolId(userPoolId),
|
|
255
|
+
userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn),
|
|
256
|
+
},
|
|
257
|
+
jsonReq,
|
|
258
|
+
);
|
|
259
|
+
}
|
|
189
260
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
261
|
+
throw new AuthError({
|
|
262
|
+
name: AuthErrorCodes.SignInException,
|
|
263
|
+
message: `Cannot proceed with MFA setup using challengeResponse: ${challengeResponse}`,
|
|
264
|
+
recoverySuggestion:
|
|
265
|
+
'Try passing "EMAIL", "TOTP", a valid email, or OTP code as the challengeResponse.',
|
|
194
266
|
});
|
|
195
|
-
|
|
196
|
-
return respondToAuthChallenge(
|
|
197
|
-
{ region: getRegionFromUserPoolId(userPoolId) },
|
|
198
|
-
jsonReq,
|
|
199
|
-
);
|
|
200
267
|
}
|
|
201
268
|
|
|
202
269
|
export async function handleSelectMFATypeChallenge({
|
|
@@ -208,7 +275,9 @@ export async function handleSelectMFATypeChallenge({
|
|
|
208
275
|
}: HandleAuthChallengeRequest): Promise<RespondToAuthChallengeCommandOutput> {
|
|
209
276
|
const { userPoolId, userPoolClientId, userPoolEndpoint } = config;
|
|
210
277
|
assertValidationError(
|
|
211
|
-
challengeResponse === 'TOTP' ||
|
|
278
|
+
challengeResponse === 'TOTP' ||
|
|
279
|
+
challengeResponse === 'SMS' ||
|
|
280
|
+
challengeResponse === 'EMAIL',
|
|
212
281
|
AuthValidationErrorCode.IncorrectMFAMethod,
|
|
213
282
|
);
|
|
214
283
|
|
|
@@ -247,88 +316,6 @@ export async function handleSelectMFATypeChallenge({
|
|
|
247
316
|
);
|
|
248
317
|
}
|
|
249
318
|
|
|
250
|
-
export async function handleSMSMFAChallenge({
|
|
251
|
-
challengeResponse,
|
|
252
|
-
clientMetadata,
|
|
253
|
-
session,
|
|
254
|
-
username,
|
|
255
|
-
config,
|
|
256
|
-
}: HandleAuthChallengeRequest): Promise<RespondToAuthChallengeCommandOutput> {
|
|
257
|
-
const { userPoolId, userPoolClientId, userPoolEndpoint } = config;
|
|
258
|
-
const challengeResponses = {
|
|
259
|
-
USERNAME: username,
|
|
260
|
-
SMS_MFA_CODE: challengeResponse,
|
|
261
|
-
};
|
|
262
|
-
const UserContextData = getUserContextData({
|
|
263
|
-
username,
|
|
264
|
-
userPoolId,
|
|
265
|
-
userPoolClientId,
|
|
266
|
-
});
|
|
267
|
-
const jsonReq: RespondToAuthChallengeCommandInput = {
|
|
268
|
-
ChallengeName: 'SMS_MFA',
|
|
269
|
-
ChallengeResponses: challengeResponses,
|
|
270
|
-
Session: session,
|
|
271
|
-
ClientMetadata: clientMetadata,
|
|
272
|
-
ClientId: userPoolClientId,
|
|
273
|
-
UserContextData,
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
const respondToAuthChallenge = createRespondToAuthChallengeClient({
|
|
277
|
-
endpointResolver: createCognitoUserPoolEndpointResolver({
|
|
278
|
-
endpointOverride: userPoolEndpoint,
|
|
279
|
-
}),
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
return respondToAuthChallenge(
|
|
283
|
-
{
|
|
284
|
-
region: getRegionFromUserPoolId(userPoolId),
|
|
285
|
-
userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn),
|
|
286
|
-
},
|
|
287
|
-
jsonReq,
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
export async function handleSoftwareTokenMFAChallenge({
|
|
291
|
-
challengeResponse,
|
|
292
|
-
clientMetadata,
|
|
293
|
-
session,
|
|
294
|
-
username,
|
|
295
|
-
config,
|
|
296
|
-
}: HandleAuthChallengeRequest): Promise<RespondToAuthChallengeCommandOutput> {
|
|
297
|
-
const { userPoolId, userPoolClientId, userPoolEndpoint } = config;
|
|
298
|
-
const challengeResponses = {
|
|
299
|
-
USERNAME: username,
|
|
300
|
-
SOFTWARE_TOKEN_MFA_CODE: challengeResponse,
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
const UserContextData = getUserContextData({
|
|
304
|
-
username,
|
|
305
|
-
userPoolId,
|
|
306
|
-
userPoolClientId,
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
const jsonReq: RespondToAuthChallengeCommandInput = {
|
|
310
|
-
ChallengeName: 'SOFTWARE_TOKEN_MFA',
|
|
311
|
-
ChallengeResponses: challengeResponses,
|
|
312
|
-
Session: session,
|
|
313
|
-
ClientMetadata: clientMetadata,
|
|
314
|
-
ClientId: userPoolClientId,
|
|
315
|
-
UserContextData,
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
const respondToAuthChallenge = createRespondToAuthChallengeClient({
|
|
319
|
-
endpointResolver: createCognitoUserPoolEndpointResolver({
|
|
320
|
-
endpointOverride: userPoolEndpoint,
|
|
321
|
-
}),
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
return respondToAuthChallenge(
|
|
325
|
-
{
|
|
326
|
-
region: getRegionFromUserPoolId(userPoolId),
|
|
327
|
-
userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn),
|
|
328
|
-
},
|
|
329
|
-
jsonReq,
|
|
330
|
-
);
|
|
331
|
-
}
|
|
332
319
|
export async function handleCompleteNewPasswordChallenge({
|
|
333
320
|
challengeResponse,
|
|
334
321
|
clientMetadata,
|
|
@@ -842,37 +829,65 @@ export async function getSignInResult(params: {
|
|
|
842
829
|
case 'MFA_SETUP': {
|
|
843
830
|
const { signInSession, username } = signInStore.getState();
|
|
844
831
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
832
|
+
const mfaSetupTypes =
|
|
833
|
+
getMFATypes(parseMFATypes(challengeParameters.MFAS_CAN_SETUP)) || [];
|
|
834
|
+
|
|
835
|
+
const allowedMfaSetupTypes = getAllowedMfaSetupTypes(mfaSetupTypes);
|
|
836
|
+
|
|
837
|
+
const isTotpMfaSetupAvailable = allowedMfaSetupTypes.includes('TOTP');
|
|
838
|
+
const isEmailMfaSetupAvailable = allowedMfaSetupTypes.includes('EMAIL');
|
|
839
|
+
|
|
840
|
+
if (isTotpMfaSetupAvailable && isEmailMfaSetupAvailable) {
|
|
841
|
+
return {
|
|
842
|
+
isSignedIn: false,
|
|
843
|
+
nextStep: {
|
|
844
|
+
signInStep: 'CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION',
|
|
845
|
+
allowedMFATypes: allowedMfaSetupTypes,
|
|
846
|
+
},
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (isEmailMfaSetupAvailable) {
|
|
851
|
+
return {
|
|
852
|
+
isSignedIn: false,
|
|
853
|
+
nextStep: {
|
|
854
|
+
signInStep: 'CONTINUE_SIGN_IN_WITH_EMAIL_SETUP',
|
|
855
|
+
},
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
if (isTotpMfaSetupAvailable) {
|
|
860
|
+
const associateSoftwareToken = createAssociateSoftwareTokenClient({
|
|
861
|
+
endpointResolver: createCognitoUserPoolEndpointResolver({
|
|
862
|
+
endpointOverride: authConfig.userPoolEndpoint,
|
|
863
|
+
}),
|
|
864
|
+
});
|
|
865
|
+
const { Session, SecretCode: secretCode } =
|
|
866
|
+
await associateSoftwareToken(
|
|
867
|
+
{ region: getRegionFromUserPoolId(authConfig.userPoolId) },
|
|
868
|
+
{
|
|
869
|
+
Session: signInSession,
|
|
870
|
+
},
|
|
871
|
+
);
|
|
872
|
+
|
|
873
|
+
signInStore.dispatch({
|
|
874
|
+
type: 'SET_SIGN_IN_SESSION',
|
|
875
|
+
value: Session,
|
|
851
876
|
});
|
|
852
877
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
Session: signInSession,
|
|
862
|
-
},
|
|
863
|
-
);
|
|
864
|
-
signInStore.dispatch({
|
|
865
|
-
type: 'SET_SIGN_IN_SESSION',
|
|
866
|
-
value: Session,
|
|
867
|
-
});
|
|
878
|
+
return {
|
|
879
|
+
isSignedIn: false,
|
|
880
|
+
nextStep: {
|
|
881
|
+
signInStep: 'CONTINUE_SIGN_IN_WITH_TOTP_SETUP',
|
|
882
|
+
totpSetupDetails: getTOTPSetupDetails(secretCode!, username),
|
|
883
|
+
},
|
|
884
|
+
};
|
|
885
|
+
}
|
|
868
886
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
totpSetupDetails: getTOTPSetupDetails(secretCode!, username),
|
|
874
|
-
},
|
|
875
|
-
};
|
|
887
|
+
throw new AuthError({
|
|
888
|
+
name: AuthErrorCodes.SignInException,
|
|
889
|
+
message: `Cannot initiate MFA setup from available types: ${mfaSetupTypes}`,
|
|
890
|
+
});
|
|
876
891
|
}
|
|
877
892
|
case 'NEW_PASSWORD_REQUIRED':
|
|
878
893
|
return {
|
|
@@ -913,6 +928,18 @@ export async function getSignInResult(params: {
|
|
|
913
928
|
signInStep: 'CONFIRM_SIGN_IN_WITH_TOTP_CODE',
|
|
914
929
|
},
|
|
915
930
|
};
|
|
931
|
+
case 'EMAIL_OTP':
|
|
932
|
+
return {
|
|
933
|
+
isSignedIn: false,
|
|
934
|
+
nextStep: {
|
|
935
|
+
signInStep: 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE',
|
|
936
|
+
codeDeliveryDetails: {
|
|
937
|
+
deliveryMedium:
|
|
938
|
+
challengeParameters.CODE_DELIVERY_DELIVERY_MEDIUM as AuthDeliveryMedium,
|
|
939
|
+
destination: challengeParameters.CODE_DELIVERY_DESTINATION,
|
|
940
|
+
},
|
|
941
|
+
},
|
|
942
|
+
};
|
|
916
943
|
case 'ADMIN_NO_SRP_AUTH':
|
|
917
944
|
break;
|
|
918
945
|
case 'DEVICE_PASSWORD_VERIFIER':
|
|
@@ -1000,14 +1027,6 @@ export async function handleChallengeName(
|
|
|
1000
1027
|
const deviceName = options?.friendlyDeviceName;
|
|
1001
1028
|
|
|
1002
1029
|
switch (challengeName) {
|
|
1003
|
-
case 'SMS_MFA':
|
|
1004
|
-
return handleSMSMFAChallenge({
|
|
1005
|
-
challengeResponse,
|
|
1006
|
-
clientMetadata,
|
|
1007
|
-
session,
|
|
1008
|
-
username,
|
|
1009
|
-
config,
|
|
1010
|
-
});
|
|
1011
1030
|
case 'SELECT_MFA_TYPE':
|
|
1012
1031
|
return handleSelectMFATypeChallenge({
|
|
1013
1032
|
challengeResponse,
|
|
@@ -1050,8 +1069,11 @@ export async function handleChallengeName(
|
|
|
1050
1069
|
username,
|
|
1051
1070
|
tokenOrchestrator,
|
|
1052
1071
|
);
|
|
1072
|
+
case 'SMS_MFA':
|
|
1053
1073
|
case 'SOFTWARE_TOKEN_MFA':
|
|
1054
|
-
|
|
1074
|
+
case 'EMAIL_OTP':
|
|
1075
|
+
return handleMFAChallenge({
|
|
1076
|
+
challengeName,
|
|
1055
1077
|
challengeResponse,
|
|
1056
1078
|
clientMetadata,
|
|
1057
1079
|
session,
|
|
@@ -1062,7 +1084,7 @@ export async function handleChallengeName(
|
|
|
1062
1084
|
// TODO: remove this error message for production apps
|
|
1063
1085
|
throw new AuthError({
|
|
1064
1086
|
name: AuthErrorCodes.SignInException,
|
|
1065
|
-
message: `An error occurred during the sign in process.
|
|
1087
|
+
message: `An error occurred during the sign in process.
|
|
1066
1088
|
${challengeName} challengeName returned by the underlying service was not addressed.`,
|
|
1067
1089
|
});
|
|
1068
1090
|
}
|
|
@@ -1070,6 +1092,7 @@ export async function handleChallengeName(
|
|
|
1070
1092
|
export function mapMfaType(mfa: string): CognitoMFAType {
|
|
1071
1093
|
let mfaType: CognitoMFAType = 'SMS_MFA';
|
|
1072
1094
|
if (mfa === 'TOTP') mfaType = 'SOFTWARE_TOKEN_MFA';
|
|
1095
|
+
if (mfa === 'EMAIL') mfaType = 'EMAIL_OTP';
|
|
1073
1096
|
|
|
1074
1097
|
return mfaType;
|
|
1075
1098
|
}
|
|
@@ -1077,6 +1100,7 @@ export function mapMfaType(mfa: string): CognitoMFAType {
|
|
|
1077
1100
|
export function getMFAType(type?: string): AuthMFAType | undefined {
|
|
1078
1101
|
if (type === 'SMS_MFA') return 'SMS';
|
|
1079
1102
|
if (type === 'SOFTWARE_TOKEN_MFA') return 'TOTP';
|
|
1103
|
+
if (type === 'EMAIL_OTP') return 'EMAIL';
|
|
1080
1104
|
// TODO: log warning for unknown MFA type
|
|
1081
1105
|
}
|
|
1082
1106
|
|
|
@@ -1091,15 +1115,10 @@ export function parseMFATypes(mfa?: string): CognitoMFAType[] {
|
|
|
1091
1115
|
return JSON.parse(mfa) as CognitoMFAType[];
|
|
1092
1116
|
}
|
|
1093
1117
|
|
|
1094
|
-
export function
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
)
|
|
1098
|
-
const { MFAS_CAN_SETUP } = challengeParams;
|
|
1099
|
-
const mfaTypes = getMFATypes(parseMFATypes(MFAS_CAN_SETUP));
|
|
1100
|
-
if (!mfaTypes) return false;
|
|
1101
|
-
|
|
1102
|
-
return mfaTypes.includes(mfaType);
|
|
1118
|
+
export function getAllowedMfaSetupTypes(availableMfaSetupTypes: AuthMFAType[]) {
|
|
1119
|
+
return availableMfaSetupTypes.filter(
|
|
1120
|
+
authMfaType => authMfaType === 'EMAIL' || authMfaType === 'TOTP',
|
|
1121
|
+
);
|
|
1103
1122
|
}
|
|
1104
1123
|
|
|
1105
1124
|
export async function assertUserNotAuthenticated() {
|
|
@@ -1230,3 +1249,64 @@ export function getActiveSignInUsername(username: string): string {
|
|
|
1230
1249
|
|
|
1231
1250
|
return state.username ?? username;
|
|
1232
1251
|
}
|
|
1252
|
+
|
|
1253
|
+
export async function handleMFAChallenge({
|
|
1254
|
+
challengeName,
|
|
1255
|
+
challengeResponse,
|
|
1256
|
+
clientMetadata,
|
|
1257
|
+
session,
|
|
1258
|
+
username,
|
|
1259
|
+
config,
|
|
1260
|
+
}: HandleAuthChallengeRequest & {
|
|
1261
|
+
challengeName: Extract<
|
|
1262
|
+
ChallengeName,
|
|
1263
|
+
'EMAIL_OTP' | 'SMS_MFA' | 'SOFTWARE_TOKEN_MFA'
|
|
1264
|
+
>;
|
|
1265
|
+
}) {
|
|
1266
|
+
const { userPoolId, userPoolClientId, userPoolEndpoint } = config;
|
|
1267
|
+
|
|
1268
|
+
const challengeResponses: Record<string, string> = {
|
|
1269
|
+
USERNAME: username,
|
|
1270
|
+
};
|
|
1271
|
+
|
|
1272
|
+
if (challengeName === 'EMAIL_OTP') {
|
|
1273
|
+
challengeResponses.EMAIL_OTP_CODE = challengeResponse;
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
if (challengeName === 'SMS_MFA') {
|
|
1277
|
+
challengeResponses.SMS_MFA_CODE = challengeResponse;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
if (challengeName === 'SOFTWARE_TOKEN_MFA') {
|
|
1281
|
+
challengeResponses.SOFTWARE_TOKEN_MFA_CODE = challengeResponse;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
const userContextData = getUserContextData({
|
|
1285
|
+
username,
|
|
1286
|
+
userPoolId,
|
|
1287
|
+
userPoolClientId,
|
|
1288
|
+
});
|
|
1289
|
+
|
|
1290
|
+
const jsonReq: RespondToAuthChallengeCommandInput = {
|
|
1291
|
+
ChallengeName: challengeName,
|
|
1292
|
+
ChallengeResponses: challengeResponses,
|
|
1293
|
+
Session: session,
|
|
1294
|
+
ClientMetadata: clientMetadata,
|
|
1295
|
+
ClientId: userPoolClientId,
|
|
1296
|
+
UserContextData: userContextData,
|
|
1297
|
+
};
|
|
1298
|
+
|
|
1299
|
+
const respondToAuthChallenge = createRespondToAuthChallengeClient({
|
|
1300
|
+
endpointResolver: createCognitoUserPoolEndpointResolver({
|
|
1301
|
+
endpointOverride: userPoolEndpoint,
|
|
1302
|
+
}),
|
|
1303
|
+
});
|
|
1304
|
+
|
|
1305
|
+
return respondToAuthChallenge(
|
|
1306
|
+
{
|
|
1307
|
+
region: getRegionFromUserPoolId(userPoolId),
|
|
1308
|
+
userAgentValue: getAuthUserAgentValue(AuthAction.ConfirmSignIn),
|
|
1309
|
+
},
|
|
1310
|
+
jsonReq,
|
|
1311
|
+
);
|
|
1312
|
+
}
|
package/src/types/models.ts
CHANGED
|
@@ -44,7 +44,7 @@ export interface AuthTOTPSetupDetails {
|
|
|
44
44
|
getSetupUri(appName: string, accountName?: string): URL;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export type AuthMFAType = 'SMS' | 'TOTP';
|
|
47
|
+
export type AuthMFAType = 'SMS' | 'TOTP' | 'EMAIL';
|
|
48
48
|
|
|
49
49
|
export type AuthAllowedMFATypes = AuthMFAType[];
|
|
50
50
|
|
|
@@ -63,6 +63,20 @@ export interface ContinueSignInWithTOTPSetup {
|
|
|
63
63
|
signInStep: 'CONTINUE_SIGN_IN_WITH_TOTP_SETUP';
|
|
64
64
|
totpSetupDetails: AuthTOTPSetupDetails;
|
|
65
65
|
}
|
|
66
|
+
export interface ContinueSignInWithEmailSetup {
|
|
67
|
+
/**
|
|
68
|
+
* Auth step requires user to set up EMAIL as multifactor authentication by associating an email address
|
|
69
|
+
* and entering the OTP.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* // Code retrieved from email
|
|
74
|
+
* const emailAddress = 'example@example.com';
|
|
75
|
+
* await confirmSignIn({challengeResponse: emailAddress });
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
signInStep: 'CONTINUE_SIGN_IN_WITH_EMAIL_SETUP';
|
|
79
|
+
}
|
|
66
80
|
export interface ConfirmSignInWithTOTPCode {
|
|
67
81
|
/**
|
|
68
82
|
* Auth step requires user to use TOTP as multifactor authentication by retriving an OTP code from authenticator app.
|
|
@@ -92,6 +106,21 @@ export interface ContinueSignInWithMFASelection {
|
|
|
92
106
|
allowedMFATypes?: AuthAllowedMFATypes;
|
|
93
107
|
}
|
|
94
108
|
|
|
109
|
+
export interface ContinueSignInWithMFASetupSelection {
|
|
110
|
+
/**
|
|
111
|
+
* Auth step requires user to select an mfa option (SMS | TOTP) to setup before continuing the sign-in flow.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* await confirmSignIn({challengeResponse:'TOTP'});
|
|
116
|
+
* // OR
|
|
117
|
+
* await confirmSignIn({challengeResponse:'EMAIL'});
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
signInStep: 'CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION';
|
|
121
|
+
allowedMFATypes?: AuthAllowedMFATypes;
|
|
122
|
+
}
|
|
123
|
+
|
|
95
124
|
export interface ConfirmSignInWithCustomChallenge {
|
|
96
125
|
/**
|
|
97
126
|
* Auth step requires user to respond to a custom challenge.
|
|
@@ -146,6 +175,21 @@ export interface ConfirmSignInWithSMSCode {
|
|
|
146
175
|
codeDeliveryDetails?: AuthCodeDeliveryDetails;
|
|
147
176
|
}
|
|
148
177
|
|
|
178
|
+
export interface ConfirmSignInWithEmailCode {
|
|
179
|
+
/**
|
|
180
|
+
* Auth step requires user to use EMAIL as multifactor authentication by retrieving a code sent to inbox.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* // Code retrieved from email
|
|
185
|
+
* const emailCode = '112233'
|
|
186
|
+
* await confirmSignIn({challengeResponse: emailCode})
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
signInStep: 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE';
|
|
190
|
+
codeDeliveryDetails?: AuthCodeDeliveryDetails;
|
|
191
|
+
}
|
|
192
|
+
|
|
149
193
|
export interface ConfirmSignUpStep {
|
|
150
194
|
/**
|
|
151
195
|
* Auth step requires to confirm user's sign-up.
|
|
@@ -181,7 +225,10 @@ export type AuthNextSignInStep<
|
|
|
181
225
|
| ConfirmSignInWithNewPasswordRequired<UserAttributeKey>
|
|
182
226
|
| ConfirmSignInWithSMSCode
|
|
183
227
|
| ConfirmSignInWithTOTPCode
|
|
228
|
+
| ConfirmSignInWithEmailCode
|
|
184
229
|
| ContinueSignInWithTOTPSetup
|
|
230
|
+
| ContinueSignInWithEmailSetup
|
|
231
|
+
| ContinueSignInWithMFASetupSelection
|
|
185
232
|
| ConfirmSignUpStep
|
|
186
233
|
| ResetPasswordStep
|
|
187
234
|
| DoneSignInStep;
|