@aws-amplify/ui 6.12.1 → 6.14.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/esm/helpers/authenticator/facade.mjs +9 -2
- package/dist/esm/helpers/authenticator/formFields/defaults.mjs +34 -8
- package/dist/esm/helpers/authenticator/getRoute.mjs +8 -0
- package/dist/esm/helpers/authenticator/textUtil.mjs +34 -0
- package/dist/esm/i18n/dictionaries/authenticator/defaultTexts.mjs +27 -0
- package/dist/esm/i18n/dictionaries/authenticator/es.mjs +1 -1
- package/dist/esm/i18n/dictionaries/authenticator/fr.mjs +1 -1
- package/dist/esm/machines/authenticator/actions.mjs +63 -4
- package/dist/esm/machines/authenticator/actors/signIn.mjs +199 -49
- package/dist/esm/machines/authenticator/actors/signUp.mjs +81 -27
- package/dist/esm/machines/authenticator/defaultServices.mjs +37 -0
- package/dist/esm/machines/authenticator/guards.mjs +49 -1
- package/dist/esm/machines/authenticator/index.mjs +29 -15
- package/dist/esm/machines/authenticator/utils.mjs +65 -6
- package/dist/index.js +632 -111
- package/dist/styles/authenticator.css +17 -0
- package/dist/styles/authenticator.layer.css +17 -0
- package/dist/styles.css +17 -0
- package/dist/styles.layer.css +17 -0
- package/dist/types/helpers/authenticator/facade.d.ts +6 -2
- package/dist/types/helpers/authenticator/textUtil.d.ts +24 -1
- package/dist/types/i18n/dictionaries/authenticator/defaultTexts.d.ts +27 -0
- package/dist/types/i18n/dictionaries/index.d.ts +27 -0
- package/dist/types/i18n/translations.d.ts +27 -0
- package/dist/types/machines/authenticator/defaultServices.d.ts +105 -0
- package/dist/types/machines/authenticator/types.d.ts +26 -2
- package/dist/types/machines/authenticator/utils.d.ts +14 -2
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -1117,7 +1117,7 @@ const esDict$1 = {
|
|
|
1117
1117
|
'Sign Up with Google': 'Crear cuenta con Google',
|
|
1118
1118
|
'Sign Up': 'Crear cuenta',
|
|
1119
1119
|
'User already exists': 'El usuario ya existe',
|
|
1120
|
-
'User does not exist': 'El usuario no existe',
|
|
1120
|
+
'User does not exist.': 'El usuario no existe',
|
|
1121
1121
|
'Username/client id combination not found.': 'El usuario no existe',
|
|
1122
1122
|
'Username cannot be empty': 'El nombre de usuario no puede estar vacío',
|
|
1123
1123
|
'Your passwords must match': 'Las contraseñas deben coincidir',
|
|
@@ -1244,7 +1244,7 @@ const frDict$1 = {
|
|
|
1244
1244
|
'Sign Up': "S'inscrire",
|
|
1245
1245
|
SMS: 'SMS',
|
|
1246
1246
|
'User already exists': "L'utilisateur existe déjà",
|
|
1247
|
-
'User does not exist': "L'utilisateur n'existe pas",
|
|
1247
|
+
'User does not exist.': "L'utilisateur n'existe pas",
|
|
1248
1248
|
'Username cannot be empty': "Le nom d'utilisateur doit être renseigné",
|
|
1249
1249
|
'Username/client id combination not found.': "L'utilisateur n'existe pas",
|
|
1250
1250
|
'We Emailed You': 'Nous vous avons envoyé un code',
|
|
@@ -2770,7 +2770,13 @@ const defaultTexts$1 = {
|
|
|
2770
2770
|
CONFIRM: 'Confirm',
|
|
2771
2771
|
CONFIRMATION_CODE: 'Confirmation Code',
|
|
2772
2772
|
CONFIRMING: 'Confirming',
|
|
2773
|
+
CONTINUE: 'Continue',
|
|
2774
|
+
CONTINUE_WITHOUT_PASSKEY: 'Continue without a Passkey',
|
|
2773
2775
|
CREATE_ACCOUNT: 'Create Account',
|
|
2776
|
+
CREATE_ACCOUNT_WITH_EMAIL_OTP: 'Create account with Email OTP',
|
|
2777
|
+
CREATE_ACCOUNT_WITH_PASSWORD: 'Create account with Password',
|
|
2778
|
+
CREATE_ACCOUNT_WITH_SMS_OTP: 'Create account with SMS OTP',
|
|
2779
|
+
CREATE_PASSKEY: 'Create a Passkey',
|
|
2774
2780
|
CREATING_ACCOUNT: 'Creating Account',
|
|
2775
2781
|
EMAIL_ADDRESS: 'Email',
|
|
2776
2782
|
EMAIL_OTP: 'Email Message',
|
|
@@ -2787,6 +2793,8 @@ const defaultTexts$1 = {
|
|
|
2787
2793
|
ENTER_PHONE_NUMBER: 'Enter your Phone Number',
|
|
2788
2794
|
ENTER_PREFERRED_USERNAME: 'Enter your Preferred Username',
|
|
2789
2795
|
ENTER_USERNAME: 'Enter your username',
|
|
2796
|
+
ENTER_USERNAME_FIRST: 'Please enter your username first',
|
|
2797
|
+
EXISTING_PASSKEYS: 'Existing Passkeys',
|
|
2790
2798
|
FAMILY_NAME: 'Family Name',
|
|
2791
2799
|
GIVEN_NAME: 'Given Name',
|
|
2792
2800
|
FORGOT_PASSWORD: 'Forgot Password?',
|
|
@@ -2801,16 +2809,30 @@ const defaultTexts$1 = {
|
|
|
2801
2809
|
NICKNAME: 'Nickname',
|
|
2802
2810
|
NEW_PASSWORD: 'New password',
|
|
2803
2811
|
OR: 'or',
|
|
2812
|
+
OTHER_SIGN_IN_OPTIONS: 'Other sign-in options',
|
|
2813
|
+
PASSKEY_AUTHENTICATION_CANCELED: 'Passkey authentication was canceled. Please try again or use a different sign-in method.',
|
|
2814
|
+
PASSKEY_CREATED_SUCCESS: 'Passkey created successfully!',
|
|
2815
|
+
PASSKEY_LABEL: 'Passkey',
|
|
2816
|
+
PASSKEY_PROMPT_DESCRIPTION: 'Passkeys are WebAuthn credentials that validate your identity using biometric data like touch or facial recognition or device authentication like passwords or PINs, serving as a secure password replacement.',
|
|
2817
|
+
PASSKEY_PROMPT_HEADING: 'Sign in faster with Passkey',
|
|
2818
|
+
PASSKEY_REGISTERED: 'Your passkey has been successfully registered.',
|
|
2819
|
+
PASSKEY_REGISTRATION_FAILED: 'Failed to create passkey. Please try again.',
|
|
2804
2820
|
PASSWORD: 'Password',
|
|
2821
|
+
PASSWORDLESS_NOT_ENABLED: 'Passwordless authentication is not enabled for this account. Please contact your administrator or use password sign-in.',
|
|
2805
2822
|
PHONE_NUMBER: 'Phone Number',
|
|
2806
2823
|
PREFERRED_USERNAME: 'Preferred Username',
|
|
2807
2824
|
PROFILE: 'Profile',
|
|
2825
|
+
REGISTERING: 'Registering',
|
|
2808
2826
|
RESEND_CODE: 'Resend Code',
|
|
2809
2827
|
RESET_PASSWORD_HEADING: 'Reset your password',
|
|
2810
2828
|
RESET_PASSWORD: 'Reset Password',
|
|
2811
2829
|
SEND_CODE: 'Send code',
|
|
2830
|
+
CODE_DELIVERY_FAILED: 'Unable to send verification code. Please try again.',
|
|
2831
|
+
VERIFICATION_CODE_EXPIRED: 'Your verification code has expired. Please request a new code.',
|
|
2832
|
+
VERIFICATION_CODE_INVALID: 'The verification code you entered is incorrect. Please try again.',
|
|
2812
2833
|
SENDING: 'Sending',
|
|
2813
2834
|
SELECT_MFA_TYPE: 'Select MFA Type',
|
|
2835
|
+
SETUP_ANOTHER_PASSKEY: 'Setup another Passkey',
|
|
2814
2836
|
SETUP_EMAIL: 'Setup Email',
|
|
2815
2837
|
SETUP_TOTP: 'Setup TOTP',
|
|
2816
2838
|
SHOW_PASSWORD: 'Show password',
|
|
@@ -2818,8 +2840,12 @@ const defaultTexts$1 = {
|
|
|
2818
2840
|
SIGN_IN_TAB: 'Sign In',
|
|
2819
2841
|
SIGN_IN_WITH_AMAZON: 'Sign In with Amazon',
|
|
2820
2842
|
SIGN_IN_WITH_APPLE: 'Sign In with Apple',
|
|
2843
|
+
SIGN_IN_WITH_EMAIL: 'Sign In with Email',
|
|
2821
2844
|
SIGN_IN_WITH_FACEBOOK: 'Sign In with Facebook',
|
|
2822
2845
|
SIGN_IN_WITH_GOOGLE: 'Sign In with Google',
|
|
2846
|
+
SIGN_IN_WITH_PASSKEY: 'Sign In with Passkey',
|
|
2847
|
+
SIGN_IN_WITH_PASSWORD: 'Sign In with Password',
|
|
2848
|
+
SIGN_IN_WITH_SMS: 'Sign In with SMS',
|
|
2823
2849
|
SIGN_IN: 'Sign in to your account',
|
|
2824
2850
|
SIGN_UP_BUTTON: 'Create a new account',
|
|
2825
2851
|
SIGNING_IN_BUTTON: 'Signing in',
|
|
@@ -2829,6 +2855,7 @@ const defaultTexts$1 = {
|
|
|
2829
2855
|
SUBMITTING: 'Submitting',
|
|
2830
2856
|
SOFTWARE_TOKEN_MFA: 'Authenticator App (TOTP)',
|
|
2831
2857
|
UPPERCASE_COPY: 'COPY',
|
|
2858
|
+
USERNAME: 'Username',
|
|
2832
2859
|
VERIFY_CONTACT: 'Verify Contact',
|
|
2833
2860
|
VERIFY_HEADING: 'Account recovery requires verified contact information',
|
|
2834
2861
|
VERIFY: 'Verify',
|
|
@@ -3100,6 +3127,14 @@ const getRoute = (state, actorState) => {
|
|
|
3100
3127
|
case actorState?.matches('setupTotp.edit'):
|
|
3101
3128
|
case actorState?.matches('setupTotp.submit'):
|
|
3102
3129
|
return 'setupTotp';
|
|
3130
|
+
case actorState?.matches('signIn.submit'):
|
|
3131
|
+
return actorState?.context.selectedAuthMethod != null
|
|
3132
|
+
? 'signInSelectAuthFactor'
|
|
3133
|
+
: 'signIn';
|
|
3134
|
+
case actorState?.matches('signIn.selectMethod'):
|
|
3135
|
+
return 'signInSelectAuthFactor';
|
|
3136
|
+
case actorState?.matches('passkeyPrompt'):
|
|
3137
|
+
return 'passkeyPrompt';
|
|
3103
3138
|
case actorState?.matches('signIn'):
|
|
3104
3139
|
return 'signIn';
|
|
3105
3140
|
case actorState?.matches('signUp'):
|
|
@@ -3157,8 +3192,10 @@ const getSendEventAliases = (send) => {
|
|
|
3157
3192
|
return {
|
|
3158
3193
|
initializeMachine: sendToMachine('INIT'),
|
|
3159
3194
|
resendCode: sendToMachine('RESEND'),
|
|
3195
|
+
selectAuthMethod: sendToMachine('SELECT_METHOD'),
|
|
3160
3196
|
signOut: sendToMachine('SIGN_OUT'),
|
|
3161
3197
|
submitForm: sendToMachine('SUBMIT'),
|
|
3198
|
+
toShowAuthMethods: sendToMachine('SHOW_AUTH_METHODS'),
|
|
3162
3199
|
updateForm: sendToMachine('CHANGE'),
|
|
3163
3200
|
updateBlur: sendToMachine('BLUR'),
|
|
3164
3201
|
// Actions that don't immediately invoke a service but instead transition to a screen
|
|
@@ -3183,8 +3220,9 @@ const getNextSendEventAliases = (send) => {
|
|
|
3183
3220
|
};
|
|
3184
3221
|
const getServiceContextFacade = (state) => {
|
|
3185
3222
|
const actorContext = (getActorContext$1(state) ?? {});
|
|
3186
|
-
const { allowedMfaTypes, challengeName, codeDeliveryDetails, remoteError: error, validationError: validationErrors, totpSecretCode = null, unverifiedUserAttributes, username, } = actorContext;
|
|
3187
|
-
const { socialProviders = [] } = state.context?.config ?? {};
|
|
3223
|
+
const { allowedMfaTypes, availableAuthMethods, challengeName, codeDeliveryDetails, preferredChallenge, remoteError: error, selectedAuthMethod, validationError: validationErrors, totpSecretCode = null, unverifiedUserAttributes, username, } = actorContext;
|
|
3224
|
+
const { socialProviders = [], loginMechanisms } = state.context?.config ?? {};
|
|
3225
|
+
const loginMechanism = loginMechanisms?.[0];
|
|
3188
3226
|
// check for user in actorContext prior to state context. actorContext is more "up to date",
|
|
3189
3227
|
// but is not available on all states
|
|
3190
3228
|
const user = actorContext?.user ?? state.context?.user;
|
|
@@ -3208,12 +3246,16 @@ const getServiceContextFacade = (state) => {
|
|
|
3208
3246
|
const facade = {
|
|
3209
3247
|
allowedMfaTypes,
|
|
3210
3248
|
authStatus,
|
|
3249
|
+
availableAuthMethods,
|
|
3211
3250
|
challengeName,
|
|
3212
3251
|
codeDeliveryDetails,
|
|
3213
3252
|
error,
|
|
3214
3253
|
hasValidationErrors,
|
|
3215
3254
|
isPending,
|
|
3255
|
+
loginMechanism,
|
|
3256
|
+
preferredChallenge,
|
|
3216
3257
|
route,
|
|
3258
|
+
selectedAuthMethod,
|
|
3217
3259
|
socialProviders,
|
|
3218
3260
|
totpSecretCode,
|
|
3219
3261
|
unverifiedUserAttributes,
|
|
@@ -3682,16 +3724,32 @@ const getConfirmationCodeFormFields = (_) => ({
|
|
|
3682
3724
|
placeholder: 'Code',
|
|
3683
3725
|
},
|
|
3684
3726
|
});
|
|
3685
|
-
const getSignInFormFields = (state) =>
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3727
|
+
const getSignInFormFields = (state) => {
|
|
3728
|
+
const actorContext = state.context.actorRef?.getSnapshot()?.context;
|
|
3729
|
+
const availableAuthMethods = actorContext?.availableAuthMethods;
|
|
3730
|
+
const preferredChallenge = actorContext?.preferredChallenge;
|
|
3731
|
+
const shouldShowPassword = !availableAuthMethods?.length ||
|
|
3732
|
+
(availableAuthMethods.length === 1 &&
|
|
3733
|
+
availableAuthMethods[0] === 'PASSWORD') ||
|
|
3734
|
+
(availableAuthMethods.length > 1 &&
|
|
3735
|
+
(!preferredChallenge || preferredChallenge === 'PASSWORD'));
|
|
3736
|
+
const fields = {
|
|
3737
|
+
username: { ...getAliasDefaultFormField(state) },
|
|
3738
|
+
};
|
|
3739
|
+
if (shouldShowPassword) {
|
|
3740
|
+
fields.password = {
|
|
3741
|
+
...getDefaultFormField('password'),
|
|
3742
|
+
autocomplete: 'current-password',
|
|
3743
|
+
};
|
|
3744
|
+
}
|
|
3745
|
+
return fields;
|
|
3746
|
+
};
|
|
3692
3747
|
const getSignUpFormFields = (state) => {
|
|
3693
3748
|
const { loginMechanisms, signUpAttributes } = state.context.config;
|
|
3694
3749
|
const primaryAlias = getPrimaryAlias(state);
|
|
3750
|
+
const actorContext = state.context.actorRef?.getSnapshot()?.context;
|
|
3751
|
+
const availableAuthMethods = actorContext?.availableAuthMethods;
|
|
3752
|
+
const hasMultipleMethods = availableAuthMethods && availableAuthMethods.length > 1;
|
|
3695
3753
|
/**
|
|
3696
3754
|
* @migration signUp Fields created here
|
|
3697
3755
|
*/
|
|
@@ -3707,7 +3765,17 @@ const getSignUpFormFields = (state) => {
|
|
|
3707
3765
|
const fieldAttrs = fieldName === primaryAlias
|
|
3708
3766
|
? getAliasDefaultFormField(state)
|
|
3709
3767
|
: getDefaultFormField(fieldName);
|
|
3710
|
-
|
|
3768
|
+
// Make email, phone_number, password, and confirm_password optional when multiple auth methods available
|
|
3769
|
+
// Validation will check based on selected method
|
|
3770
|
+
const isOptional = hasMultipleMethods &&
|
|
3771
|
+
(fieldName === 'email' ||
|
|
3772
|
+
fieldName === 'phone_number' ||
|
|
3773
|
+
fieldName === 'password' ||
|
|
3774
|
+
fieldName === 'confirm_password');
|
|
3775
|
+
formField[fieldName] = {
|
|
3776
|
+
...fieldAttrs,
|
|
3777
|
+
...(isOptional && { isRequired: false }),
|
|
3778
|
+
};
|
|
3711
3779
|
}
|
|
3712
3780
|
else {
|
|
3713
3781
|
// There's a `custom:*` attribute or one we don't already have an implementation for
|
|
@@ -3903,6 +3971,17 @@ const getSelectMfaTypeByChallengeName = (challengeName) => {
|
|
|
3903
3971
|
}
|
|
3904
3972
|
return translate(DefaultTexts.MFA_SELECTION);
|
|
3905
3973
|
};
|
|
3974
|
+
const getUsernameLabelByLoginMechanism = (loginMechanism) => {
|
|
3975
|
+
switch (loginMechanism) {
|
|
3976
|
+
case 'email':
|
|
3977
|
+
return translate(DefaultTexts.EMAIL_ADDRESS);
|
|
3978
|
+
case 'phone_number':
|
|
3979
|
+
return translate(DefaultTexts.PHONE_NUMBER);
|
|
3980
|
+
case 'username':
|
|
3981
|
+
default:
|
|
3982
|
+
return translate(DefaultTexts.USERNAME);
|
|
3983
|
+
}
|
|
3984
|
+
};
|
|
3906
3985
|
const getMfaTypeLabelByValue = (mfaType) => {
|
|
3907
3986
|
switch (mfaType) {
|
|
3908
3987
|
case 'EMAIL':
|
|
@@ -3922,6 +4001,7 @@ const authenticatorTextUtil = {
|
|
|
3922
4001
|
getChangingText: () => translate(DefaultTexts.CHANGING_PASSWORD),
|
|
3923
4002
|
getConfirmText: () => translate(DefaultTexts.CONFIRM),
|
|
3924
4003
|
getConfirmingText: () => translate(DefaultTexts.CONFIRMING),
|
|
4004
|
+
getContinueText: () => translate(DefaultTexts.CONTINUE),
|
|
3925
4005
|
getCopyText: () => translate(DefaultTexts.UPPERCASE_COPY),
|
|
3926
4006
|
getHidePasswordText: () => translate(DefaultTexts.HIDE_PASSWORD),
|
|
3927
4007
|
getLoadingText: () => translate(DefaultTexts.LOADING),
|
|
@@ -3944,6 +4024,9 @@ const authenticatorTextUtil = {
|
|
|
3944
4024
|
/** SignUp */
|
|
3945
4025
|
getCreatingAccountText: () => translate(DefaultTexts.CREATING_ACCOUNT),
|
|
3946
4026
|
getCreateAccountText: () => translate(DefaultTexts.CREATE_ACCOUNT),
|
|
4027
|
+
getCreateAccountWithEmailText: () => translate(DefaultTexts.CREATE_ACCOUNT_WITH_EMAIL_OTP),
|
|
4028
|
+
getCreateAccountWithPasswordText: () => translate(DefaultTexts.CREATE_ACCOUNT_WITH_PASSWORD),
|
|
4029
|
+
getCreateAccountWithSmsText: () => translate(DefaultTexts.CREATE_ACCOUNT_WITH_SMS_OTP),
|
|
3947
4030
|
/** ConfirmSignUp */
|
|
3948
4031
|
getDeliveryMessageText,
|
|
3949
4032
|
getDeliveryMethodText,
|
|
@@ -3970,6 +4053,25 @@ const authenticatorTextUtil = {
|
|
|
3970
4053
|
getVerifyText: () => translate(DefaultTexts.VERIFY),
|
|
3971
4054
|
getVerifyContactText: () => translate(DefaultTexts.VERIFY_CONTACT),
|
|
3972
4055
|
getAccountRecoveryInfoText: () => translate(DefaultTexts.VERIFY_HEADING),
|
|
4056
|
+
/** Passwordless */
|
|
4057
|
+
getPasskeyPromptHeadingText: () => translate(DefaultTexts.PASSKEY_PROMPT_HEADING),
|
|
4058
|
+
getPasskeyPromptDescriptionText: () => translate(DefaultTexts.PASSKEY_PROMPT_DESCRIPTION),
|
|
4059
|
+
getCreatePasskeyText: () => translate(DefaultTexts.CREATE_PASSKEY),
|
|
4060
|
+
getRegisteringText: () => translate(DefaultTexts.REGISTERING),
|
|
4061
|
+
getContinueWithoutPasskeyText: () => translate(DefaultTexts.CONTINUE_WITHOUT_PASSKEY),
|
|
4062
|
+
getPasskeyCreatedSuccessText: () => translate(DefaultTexts.PASSKEY_CREATED_SUCCESS),
|
|
4063
|
+
getPasskeyRegisteredText: () => translate(DefaultTexts.PASSKEY_REGISTERED),
|
|
4064
|
+
getPasskeyRegistrationFailedText: () => translate(DefaultTexts.PASSKEY_REGISTRATION_FAILED),
|
|
4065
|
+
getPasskeyLabelText: () => translate(DefaultTexts.PASSKEY_LABEL),
|
|
4066
|
+
getExistingPasskeysText: () => translate(DefaultTexts.EXISTING_PASSKEYS),
|
|
4067
|
+
getSetupAnotherPasskeyText: () => translate(DefaultTexts.SETUP_ANOTHER_PASSKEY),
|
|
4068
|
+
getSignInWithPasswordText: () => translate(DefaultTexts.SIGN_IN_WITH_PASSWORD),
|
|
4069
|
+
getSignInWithEmailText: () => translate(DefaultTexts.SIGN_IN_WITH_EMAIL),
|
|
4070
|
+
getSignInWithSmsText: () => translate(DefaultTexts.SIGN_IN_WITH_SMS),
|
|
4071
|
+
getSignInWithPasskeyText: () => translate(DefaultTexts.SIGN_IN_WITH_PASSKEY),
|
|
4072
|
+
getOtherSignInOptionsText: () => translate(DefaultTexts.OTHER_SIGN_IN_OPTIONS),
|
|
4073
|
+
getEnterUsernameFirstText: () => translate(DefaultTexts.ENTER_USERNAME_FIRST),
|
|
4074
|
+
getUsernameLabelByLoginMechanism,
|
|
3973
4075
|
/** Validations */
|
|
3974
4076
|
// TODO: add defaultText
|
|
3975
4077
|
getInvalidEmailText: () => translate('Please enter a valid email'),
|
|
@@ -4162,35 +4264,99 @@ const getUserAttributes = (formValues) => {
|
|
|
4162
4264
|
}
|
|
4163
4265
|
return userAttributes;
|
|
4164
4266
|
};
|
|
4165
|
-
const getSignUpInput = (username, formValues, loginMechanism) => {
|
|
4267
|
+
const getSignUpInput = (username, formValues, loginMechanism, authMethod) => {
|
|
4166
4268
|
const { password, ...values } = formValues;
|
|
4167
4269
|
const attributes = getUserAttributes(values);
|
|
4270
|
+
const isPasswordless = authMethod && authMethod !== 'PASSWORD';
|
|
4271
|
+
// For SMS OTP, set the email channel to empty string if present to force account creation with phone number
|
|
4272
|
+
let userAttributes = attributes;
|
|
4273
|
+
if (authMethod === 'SMS_OTP' && attributes.email) {
|
|
4274
|
+
userAttributes = { ...attributes, email: '' };
|
|
4275
|
+
}
|
|
4168
4276
|
const options = {
|
|
4169
|
-
autoSignIn:
|
|
4277
|
+
autoSignIn: isPasswordless
|
|
4278
|
+
? {
|
|
4279
|
+
enabled: true,
|
|
4280
|
+
authFlowType: 'USER_AUTH',
|
|
4281
|
+
preferredChallenge: authMethod,
|
|
4282
|
+
}
|
|
4283
|
+
: DEFAULT_AUTO_SIGN_IN,
|
|
4170
4284
|
userAttributes: {
|
|
4171
4285
|
// use `username` value for `phone_number`
|
|
4172
4286
|
...(loginMechanism === 'phone_number'
|
|
4173
|
-
? { ...
|
|
4174
|
-
:
|
|
4287
|
+
? { ...userAttributes, phone_number: username }
|
|
4288
|
+
: userAttributes),
|
|
4175
4289
|
},
|
|
4176
4290
|
};
|
|
4177
|
-
return { username, password, options };
|
|
4291
|
+
return { username, password: isPasswordless ? undefined : password, options };
|
|
4178
4292
|
};
|
|
4179
4293
|
const getUsernameSignUp = ({ formValues, loginMechanisms, }) => {
|
|
4294
|
+
// Check if a specific auth method was selected via form data
|
|
4295
|
+
const authMethod = formValues.__authMethod;
|
|
4296
|
+
// For SMS_OTP, always use phone_number as username
|
|
4297
|
+
if (authMethod === 'SMS_OTP') {
|
|
4298
|
+
const { country_code, phone_number } = formValues;
|
|
4299
|
+
return sanitizePhoneNumber(country_code, phone_number);
|
|
4300
|
+
}
|
|
4301
|
+
// For EMAIL_OTP, always use email as username
|
|
4302
|
+
if (authMethod === 'EMAIL_OTP') {
|
|
4303
|
+
return formValues.email;
|
|
4304
|
+
}
|
|
4305
|
+
// When 'username' is in loginMechanisms, always use the username field for the Username parameter.
|
|
4306
|
+
// This handles both username-only mode and alias mode (username + email/phone as sign-in options).
|
|
4307
|
+
// See: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-aliases
|
|
4308
|
+
if (loginMechanisms.includes('username')) {
|
|
4309
|
+
return formValues.username;
|
|
4310
|
+
}
|
|
4180
4311
|
const loginMechanism = loginMechanisms[0];
|
|
4181
4312
|
if (loginMechanism === 'phone_number') {
|
|
4182
4313
|
const { country_code, phone_number } = formValues;
|
|
4183
4314
|
return sanitizePhoneNumber(country_code, phone_number);
|
|
4184
4315
|
}
|
|
4316
|
+
// Otherwise, use the primary login mechanism (email as username)
|
|
4185
4317
|
return formValues[loginMechanism];
|
|
4186
4318
|
};
|
|
4319
|
+
/**
|
|
4320
|
+
* Get available authentication methods based on backend capabilities and hidden methods
|
|
4321
|
+
*/
|
|
4322
|
+
const getAvailableAuthMethods = (passwordlessCapabilities, hiddenAuthMethods) => {
|
|
4323
|
+
const allMethods = [];
|
|
4324
|
+
// If hiddenAuthMethods is explicitly provided (even as empty array),
|
|
4325
|
+
// assume all methods are available and let hiddenAuthMethods filter them
|
|
4326
|
+
const assumeAllAvailable = hiddenAuthMethods !== undefined;
|
|
4327
|
+
// PASSWORD is always available by default
|
|
4328
|
+
allMethods.push('PASSWORD');
|
|
4329
|
+
// Add passwordless methods if backend supports them OR if hiddenAuthMethods is explicitly set
|
|
4330
|
+
if (assumeAllAvailable || passwordlessCapabilities?.emailOtpEnabled) {
|
|
4331
|
+
allMethods.push('EMAIL_OTP');
|
|
4332
|
+
}
|
|
4333
|
+
if (assumeAllAvailable || passwordlessCapabilities?.smsOtpEnabled) {
|
|
4334
|
+
allMethods.push('SMS_OTP');
|
|
4335
|
+
}
|
|
4336
|
+
if (assumeAllAvailable || passwordlessCapabilities?.webAuthnEnabled) {
|
|
4337
|
+
allMethods.push('WEB_AUTHN');
|
|
4338
|
+
}
|
|
4339
|
+
// Filter out hidden methods
|
|
4340
|
+
const hidden = hiddenAuthMethods ?? [];
|
|
4341
|
+
const availableMethods = allMethods.filter((method) => !hidden.includes(method));
|
|
4342
|
+
// Validate that at least one method remains
|
|
4343
|
+
if (availableMethods.length === 0) {
|
|
4344
|
+
throw new Error('InvalidPasswordlessSettings: All authentication methods are hidden');
|
|
4345
|
+
}
|
|
4346
|
+
return availableMethods;
|
|
4347
|
+
};
|
|
4187
4348
|
|
|
4188
4349
|
const { assign } = xstate.actions;
|
|
4189
4350
|
const clearActorDoneData = assign({ actorDoneData: undefined });
|
|
4190
4351
|
const clearChallengeName = assign({ challengeName: undefined });
|
|
4191
4352
|
const clearMissingAttributes = assign({ missingAttributes: undefined });
|
|
4192
4353
|
const clearError = assign({ remoteError: undefined });
|
|
4193
|
-
const clearFormValues = assign({
|
|
4354
|
+
const clearFormValues = assign({
|
|
4355
|
+
formValues: (context) => ({
|
|
4356
|
+
// Preserve username for passwordless flows to avoid "username is required" errors
|
|
4357
|
+
username: context.formValues?.username,
|
|
4358
|
+
}),
|
|
4359
|
+
});
|
|
4194
4360
|
const clearTouched = assign({ touched: {} });
|
|
4195
4361
|
const clearUser = assign({ user: undefined });
|
|
4196
4362
|
const clearValidationError = assign({ validationError: {} });
|
|
@@ -4291,7 +4457,28 @@ const setRemoteError = assign({
|
|
|
4291
4457
|
if (data.name === 'NoUserPoolError') {
|
|
4292
4458
|
return `Configuration error (see console) – please contact the administrator`;
|
|
4293
4459
|
}
|
|
4294
|
-
|
|
4460
|
+
const message = data?.message || '';
|
|
4461
|
+
// Handle USER_AUTH flow not enabled error
|
|
4462
|
+
if (message.includes('USER_AUTH flow not enabled')) {
|
|
4463
|
+
return translate(DefaultTexts.PASSWORDLESS_NOT_ENABLED);
|
|
4464
|
+
}
|
|
4465
|
+
// Handle cannot send code error
|
|
4466
|
+
if (message.includes('Cannot send code to either')) {
|
|
4467
|
+
return translate(DefaultTexts.CODE_DELIVERY_FAILED);
|
|
4468
|
+
}
|
|
4469
|
+
// Handle invalid/wrong verification code
|
|
4470
|
+
if (message.includes('Invalid code or auth state')) {
|
|
4471
|
+
return translate(DefaultTexts.VERIFICATION_CODE_INVALID);
|
|
4472
|
+
}
|
|
4473
|
+
// Handle expired verification code
|
|
4474
|
+
if (message.includes('session is expired')) {
|
|
4475
|
+
return translate(DefaultTexts.VERIFICATION_CODE_EXPIRED);
|
|
4476
|
+
}
|
|
4477
|
+
// Handle passkey authentication canceled
|
|
4478
|
+
if (message.includes('ceremony has been canceled')) {
|
|
4479
|
+
return translate(DefaultTexts.PASSKEY_AUTHENTICATION_CANCELED);
|
|
4480
|
+
}
|
|
4481
|
+
return message || data;
|
|
4295
4482
|
},
|
|
4296
4483
|
});
|
|
4297
4484
|
const setUser = assign({ user: (_, { data }) => data });
|
|
@@ -4328,8 +4515,12 @@ const handleBlur = assign({
|
|
|
4328
4515
|
}),
|
|
4329
4516
|
});
|
|
4330
4517
|
const setUnverifiedUserAttributes = assign({
|
|
4331
|
-
unverifiedUserAttributes: (
|
|
4332
|
-
|
|
4518
|
+
unverifiedUserAttributes: (context, { data }) => {
|
|
4519
|
+
// Use fetchedUserAttributes from context if data is not provided
|
|
4520
|
+
const attributes = data || context.fetchedUserAttributes;
|
|
4521
|
+
if (!attributes)
|
|
4522
|
+
return {};
|
|
4523
|
+
const { email, phone_number } = attributes;
|
|
4333
4524
|
const unverifiedUserAttributes = {
|
|
4334
4525
|
...(email && { email }),
|
|
4335
4526
|
...(phone_number && { phone_number }),
|
|
@@ -4343,11 +4534,34 @@ const setSelectedUserAttribute = assign({
|
|
|
4343
4534
|
});
|
|
4344
4535
|
// Maps to unexposed `ConfirmSignUpSignUpStep`
|
|
4345
4536
|
const setConfirmSignUpSignUpStep = assign({ step: 'CONFIRM_SIGN_UP' });
|
|
4537
|
+
// Passwordless actions
|
|
4538
|
+
const setSelectedAuthMethod = assign({
|
|
4539
|
+
selectedAuthMethod: (_, { data }) => data.method,
|
|
4540
|
+
});
|
|
4541
|
+
const setSelectedAuthMethodFromForm = assign({
|
|
4542
|
+
selectedAuthMethod: (_, { data }) => {
|
|
4543
|
+
// Extract method from form data if present, default to PASSWORD for form submissions
|
|
4544
|
+
return data?.__authMethod || 'PASSWORD';
|
|
4545
|
+
},
|
|
4546
|
+
});
|
|
4547
|
+
const setSelectAuthMethodStep = assign({
|
|
4548
|
+
step: 'SELECT_AUTH_METHOD',
|
|
4549
|
+
});
|
|
4550
|
+
const setFetchedUserAttributes = assign({
|
|
4551
|
+
fetchedUserAttributes: (_, event) => event.data,
|
|
4552
|
+
});
|
|
4553
|
+
const setHasExistingPasskeys = assign({
|
|
4554
|
+
hasExistingPasskeys: (_, event) => event.data,
|
|
4555
|
+
});
|
|
4556
|
+
const clearHasExistingPasskeys = assign({
|
|
4557
|
+
hasExistingPasskeys: false,
|
|
4558
|
+
});
|
|
4346
4559
|
const ACTIONS = {
|
|
4347
4560
|
clearActorDoneData,
|
|
4348
4561
|
clearChallengeName,
|
|
4349
4562
|
clearError,
|
|
4350
4563
|
clearFormValues,
|
|
4564
|
+
clearHasExistingPasskeys,
|
|
4351
4565
|
clearMissingAttributes,
|
|
4352
4566
|
clearSelectedUserAttribute,
|
|
4353
4567
|
clearTouched,
|
|
@@ -4359,7 +4573,9 @@ const ACTIONS = {
|
|
|
4359
4573
|
setAllowedMfaTypes,
|
|
4360
4574
|
setChallengeName,
|
|
4361
4575
|
setCodeDeliveryDetails,
|
|
4576
|
+
setFetchedUserAttributes,
|
|
4362
4577
|
setFieldErrors,
|
|
4578
|
+
setHasExistingPasskeys,
|
|
4363
4579
|
setMissingAttributes,
|
|
4364
4580
|
setNextResetPasswordStep,
|
|
4365
4581
|
setNextSignInStep,
|
|
@@ -4367,6 +4583,9 @@ const ACTIONS = {
|
|
|
4367
4583
|
setRemoteError,
|
|
4368
4584
|
setConfirmAttributeCompleteStep,
|
|
4369
4585
|
setConfirmSignUpSignUpStep,
|
|
4586
|
+
setSelectAuthMethodStep,
|
|
4587
|
+
setSelectedAuthMethod,
|
|
4588
|
+
setSelectedAuthMethodFromForm,
|
|
4370
4589
|
setShouldVerifyUserAttributeStep,
|
|
4371
4590
|
setSelectedUserAttribute,
|
|
4372
4591
|
setSignInStep,
|
|
@@ -4410,7 +4629,11 @@ const shouldResetPassword = ({ step }) => step === 'RESET_PASSWORD';
|
|
|
4410
4629
|
const shouldConfirmResetPassword = ({ step }) => step === 'CONFIRM_RESET_PASSWORD_WITH_CODE';
|
|
4411
4630
|
const shouldConfirmSignUp = ({ step }) => step === 'CONFIRM_SIGN_UP';
|
|
4412
4631
|
// miscellaneous guards
|
|
4413
|
-
const shouldVerifyAttribute = (
|
|
4632
|
+
const shouldVerifyAttribute = (context, event) => {
|
|
4633
|
+
// Try to get data from event first (for backward compatibility), then from context
|
|
4634
|
+
const data = (event.data || context.fetchedUserAttributes);
|
|
4635
|
+
if (!data)
|
|
4636
|
+
return false;
|
|
4414
4637
|
const { email, phone_number, phone_number_verified, email_verified } = data;
|
|
4415
4638
|
// if neither email nor phone_number exist
|
|
4416
4639
|
// there is nothing to verify
|
|
@@ -4435,11 +4658,51 @@ const shouldVerifyAttribute = (_, { data }) => {
|
|
|
4435
4658
|
* https://github.com/aws-amplify/amplify-ui/issues/219
|
|
4436
4659
|
*/
|
|
4437
4660
|
const isUserAlreadyConfirmed = (_, { data }) => data.message === 'User is already confirmed.';
|
|
4661
|
+
// passwordless guards
|
|
4662
|
+
const shouldSelectAuthMethod = ({ availableAuthMethods, preferredChallenge, selectedAuthMethod, }) => {
|
|
4663
|
+
// Show selection if:
|
|
4664
|
+
// 1. Multiple methods available
|
|
4665
|
+
// 2. AND either no preferredChallenge OR selectedAuthMethod is explicitly cleared (null)
|
|
4666
|
+
const hasMultipleMethods = availableAuthMethods && availableAuthMethods.length > 1;
|
|
4667
|
+
const shouldShowSelection = !preferredChallenge || selectedAuthMethod === null;
|
|
4668
|
+
return hasMultipleMethods && shouldShowSelection;
|
|
4669
|
+
};
|
|
4670
|
+
const shouldPromptPasskeyRegistration = ({ passwordless, hasExistingPasskeys, }) => {
|
|
4671
|
+
const { passkeyRegistrationPrompts } = passwordless || {};
|
|
4672
|
+
if (!passkeyRegistrationPrompts) {
|
|
4673
|
+
return false;
|
|
4674
|
+
}
|
|
4675
|
+
// Don't prompt if user already has passkeys
|
|
4676
|
+
if (hasExistingPasskeys) {
|
|
4677
|
+
return false;
|
|
4678
|
+
}
|
|
4679
|
+
if (typeof passkeyRegistrationPrompts === 'boolean') {
|
|
4680
|
+
return passkeyRegistrationPrompts;
|
|
4681
|
+
}
|
|
4682
|
+
return passkeyRegistrationPrompts.afterSignin === 'ALWAYS';
|
|
4683
|
+
};
|
|
4684
|
+
const shouldPromptPasskeyRegistrationAfterSignup = ({ passwordless, hasExistingPasskeys, }) => {
|
|
4685
|
+
const { passkeyRegistrationPrompts } = passwordless || {};
|
|
4686
|
+
if (!passkeyRegistrationPrompts) {
|
|
4687
|
+
return false;
|
|
4688
|
+
}
|
|
4689
|
+
// Don't prompt if user already has passkeys
|
|
4690
|
+
if (hasExistingPasskeys) {
|
|
4691
|
+
return false;
|
|
4692
|
+
}
|
|
4693
|
+
if (typeof passkeyRegistrationPrompts === 'boolean') {
|
|
4694
|
+
return passkeyRegistrationPrompts;
|
|
4695
|
+
}
|
|
4696
|
+
return passkeyRegistrationPrompts.afterSignup === 'ALWAYS';
|
|
4697
|
+
};
|
|
4698
|
+
const hasPasskeyRegistrationPrompts = ({ passwordless }) => passwordless?.passkeyRegistrationPrompts != null;
|
|
4699
|
+
const shouldReturnToSelectMethod = ({ selectedAuthMethod, step, }) => selectedAuthMethod != null && step === 'SELECT_AUTH_METHOD';
|
|
4438
4700
|
const GUARDS = {
|
|
4439
4701
|
hasCompletedAttributeConfirmation,
|
|
4440
4702
|
hasCompletedResetPassword,
|
|
4441
4703
|
hasCompletedSignIn,
|
|
4442
4704
|
hasCompletedSignUp,
|
|
4705
|
+
hasPasskeyRegistrationPrompts,
|
|
4443
4706
|
isConfirmSignUpStep,
|
|
4444
4707
|
isConfirmUserAttributeStep,
|
|
4445
4708
|
isResetPasswordStep,
|
|
@@ -4453,10 +4716,14 @@ const GUARDS = {
|
|
|
4453
4716
|
shouldConfirmSignUpFromSignIn,
|
|
4454
4717
|
shouldResetPassword,
|
|
4455
4718
|
shouldResetPasswordFromSignIn,
|
|
4719
|
+
shouldReturnToSelectMethod,
|
|
4720
|
+
shouldSelectAuthMethod,
|
|
4456
4721
|
shouldSetupTotp,
|
|
4457
4722
|
shouldSetupEmail,
|
|
4458
4723
|
shouldSelectMfaType,
|
|
4459
4724
|
shouldVerifyAttribute,
|
|
4725
|
+
shouldPromptPasskeyRegistration,
|
|
4726
|
+
shouldPromptPasskeyRegistrationAfterSignup,
|
|
4460
4727
|
};
|
|
4461
4728
|
|
|
4462
4729
|
// Runs all validators given. Resolves if there are no error. Rejects otherwise.
|
|
@@ -4504,11 +4771,24 @@ const defaultServices = {
|
|
|
4504
4771
|
const parsedSocialProviders = loginWith?.oauth?.providers
|
|
4505
4772
|
? loginWith.oauth.providers?.map((provider) => provider.toString().toLowerCase())
|
|
4506
4773
|
: undefined;
|
|
4774
|
+
// Detect passwordless capabilities from amplify_outputs.json
|
|
4775
|
+
// Support both snake_case (legacy) and camelCase (current) formats
|
|
4776
|
+
const passwordlessConfig = result.Auth?.Cognito?.passwordless;
|
|
4777
|
+
const passwordlessCapabilities = {
|
|
4778
|
+
emailOtpEnabled: passwordlessConfig?.emailOtpEnabled ??
|
|
4779
|
+
passwordlessConfig?.email_otp_enabled === true,
|
|
4780
|
+
smsOtpEnabled: passwordlessConfig?.smsOtpEnabled ??
|
|
4781
|
+
passwordlessConfig?.sms_otp_enabled === true,
|
|
4782
|
+
webAuthnEnabled: !!(passwordlessConfig?.webAuthn ?? passwordlessConfig?.web_authn),
|
|
4783
|
+
preferredChallenge: passwordlessConfig?.preferredChallenge ??
|
|
4784
|
+
passwordlessConfig?.preferred_challenge,
|
|
4785
|
+
};
|
|
4507
4786
|
return {
|
|
4508
4787
|
...cliConfig,
|
|
4509
4788
|
loginMechanisms: parsedLoginMechanisms,
|
|
4510
4789
|
signUpAttributes: parsedSignupAttributes,
|
|
4511
4790
|
socialProviders: parsedSocialProviders,
|
|
4791
|
+
passwordlessCapabilities,
|
|
4512
4792
|
};
|
|
4513
4793
|
},
|
|
4514
4794
|
getCurrentUser: auth.getCurrentUser,
|
|
@@ -4571,6 +4851,30 @@ const defaultServices = {
|
|
|
4571
4851
|
}
|
|
4572
4852
|
},
|
|
4573
4853
|
async validatePreferredUsername(_, __) { },
|
|
4854
|
+
async validateRequiredFieldsForAuthMethod(formData) {
|
|
4855
|
+
const authMethod = formData.__authMethod;
|
|
4856
|
+
// If no auth method specified, skip validation (will use default required fields)
|
|
4857
|
+
if (!authMethod)
|
|
4858
|
+
return null;
|
|
4859
|
+
// Check required fields based on auth method
|
|
4860
|
+
if (authMethod === 'EMAIL_OTP' && !formData.email) {
|
|
4861
|
+
return { email: 'Email is required for Email OTP sign up' };
|
|
4862
|
+
}
|
|
4863
|
+
if (authMethod === 'SMS_OTP' && !formData.phone_number) {
|
|
4864
|
+
return { phone_number: 'Phone number is required for SMS OTP sign up' };
|
|
4865
|
+
}
|
|
4866
|
+
if (authMethod === 'PASSWORD') {
|
|
4867
|
+
const errors = {};
|
|
4868
|
+
if (!formData.password) {
|
|
4869
|
+
errors.password = 'Password is required';
|
|
4870
|
+
}
|
|
4871
|
+
if (!formData.confirm_password) {
|
|
4872
|
+
errors.confirm_password = 'Confirm Password is required';
|
|
4873
|
+
}
|
|
4874
|
+
return Object.keys(errors).length > 0 ? errors : null;
|
|
4875
|
+
}
|
|
4876
|
+
return null;
|
|
4877
|
+
},
|
|
4574
4878
|
};
|
|
4575
4879
|
|
|
4576
4880
|
function forgotPasswordActor({ services, }) {
|
|
@@ -4800,32 +5104,13 @@ const handleSignInResponse = {
|
|
|
4800
5104
|
'setNextSignInStep',
|
|
4801
5105
|
'setTotpSecretCode',
|
|
4802
5106
|
'setAllowedMfaTypes',
|
|
5107
|
+
'setCodeDeliveryDetails',
|
|
4803
5108
|
],
|
|
4804
5109
|
target: '#signInActor.init',
|
|
4805
5110
|
},
|
|
4806
5111
|
],
|
|
4807
5112
|
onError: { actions: 'setRemoteError', target: 'edit' },
|
|
4808
5113
|
};
|
|
4809
|
-
const handleFetchUserAttributesResponse$1 = {
|
|
4810
|
-
onDone: [
|
|
4811
|
-
{
|
|
4812
|
-
cond: 'shouldVerifyAttribute',
|
|
4813
|
-
actions: [
|
|
4814
|
-
'setShouldVerifyUserAttributeStep',
|
|
4815
|
-
'setUnverifiedUserAttributes',
|
|
4816
|
-
],
|
|
4817
|
-
target: '#signInActor.resolved',
|
|
4818
|
-
},
|
|
4819
|
-
{
|
|
4820
|
-
actions: 'setConfirmAttributeCompleteStep',
|
|
4821
|
-
target: '#signInActor.resolved',
|
|
4822
|
-
},
|
|
4823
|
-
],
|
|
4824
|
-
onError: {
|
|
4825
|
-
actions: 'setConfirmAttributeCompleteStep',
|
|
4826
|
-
target: '#signInActor.resolved',
|
|
4827
|
-
},
|
|
4828
|
-
};
|
|
4829
5114
|
const getDefaultConfirmSignInState = (exit) => ({
|
|
4830
5115
|
initial: 'edit',
|
|
4831
5116
|
exit,
|
|
@@ -4836,6 +5121,7 @@ const getDefaultConfirmSignInState = (exit) => ({
|
|
|
4836
5121
|
SUBMIT: { actions: 'handleSubmit', target: 'submit' },
|
|
4837
5122
|
SIGN_IN: '#signInActor.signIn',
|
|
4838
5123
|
CHANGE: { actions: 'handleInput' },
|
|
5124
|
+
RESEND: { target: 'resend' },
|
|
4839
5125
|
},
|
|
4840
5126
|
},
|
|
4841
5127
|
submit: {
|
|
@@ -4843,6 +5129,21 @@ const getDefaultConfirmSignInState = (exit) => ({
|
|
|
4843
5129
|
entry: ['sendUpdate', 'clearError'],
|
|
4844
5130
|
invoke: { src: 'confirmSignIn', ...handleSignInResponse },
|
|
4845
5131
|
},
|
|
5132
|
+
resend: {
|
|
5133
|
+
tags: 'pending',
|
|
5134
|
+
entry: ['sendUpdate', 'clearError'],
|
|
5135
|
+
invoke: {
|
|
5136
|
+
src: 'resendSignInCode',
|
|
5137
|
+
onDone: {
|
|
5138
|
+
actions: ['setCodeDeliveryDetails', 'sendUpdate'],
|
|
5139
|
+
target: 'edit',
|
|
5140
|
+
},
|
|
5141
|
+
onError: {
|
|
5142
|
+
actions: 'setRemoteError',
|
|
5143
|
+
target: 'edit',
|
|
5144
|
+
},
|
|
5145
|
+
},
|
|
5146
|
+
},
|
|
4846
5147
|
},
|
|
4847
5148
|
});
|
|
4848
5149
|
function signInActor({ services }) {
|
|
@@ -4877,13 +5178,68 @@ function signInActor({ services }) {
|
|
|
4877
5178
|
{ target: 'signIn' },
|
|
4878
5179
|
],
|
|
4879
5180
|
},
|
|
4880
|
-
federatedSignIn: getFederatedSignInState('signIn'),
|
|
5181
|
+
federatedSignIn: { ...getFederatedSignInState('signIn') },
|
|
4881
5182
|
fetchUserAttributes: {
|
|
4882
5183
|
invoke: {
|
|
4883
5184
|
src: 'fetchUserAttributes',
|
|
4884
|
-
|
|
5185
|
+
onDone: [
|
|
5186
|
+
{
|
|
5187
|
+
cond: 'hasPasskeyRegistrationPrompts',
|
|
5188
|
+
actions: 'setFetchedUserAttributes',
|
|
5189
|
+
target: 'checkPasskeys',
|
|
5190
|
+
},
|
|
5191
|
+
{
|
|
5192
|
+
actions: 'setFetchedUserAttributes',
|
|
5193
|
+
target: 'evaluatePasskeyPrompt',
|
|
5194
|
+
},
|
|
5195
|
+
],
|
|
5196
|
+
onError: {
|
|
5197
|
+
actions: 'setConfirmAttributeCompleteStep',
|
|
5198
|
+
target: '#signInActor.resolved',
|
|
5199
|
+
},
|
|
5200
|
+
},
|
|
5201
|
+
},
|
|
5202
|
+
checkPasskeys: {
|
|
5203
|
+
invoke: {
|
|
5204
|
+
src: async () => {
|
|
5205
|
+
try {
|
|
5206
|
+
const result = await auth.listWebAuthnCredentials();
|
|
5207
|
+
return result.credentials && result.credentials.length > 0;
|
|
5208
|
+
}
|
|
5209
|
+
catch {
|
|
5210
|
+
return false;
|
|
5211
|
+
}
|
|
5212
|
+
},
|
|
5213
|
+
onDone: {
|
|
5214
|
+
actions: 'setHasExistingPasskeys',
|
|
5215
|
+
target: 'evaluatePasskeyPrompt',
|
|
5216
|
+
},
|
|
5217
|
+
onError: {
|
|
5218
|
+
actions: 'clearHasExistingPasskeys',
|
|
5219
|
+
target: 'evaluatePasskeyPrompt',
|
|
5220
|
+
},
|
|
4885
5221
|
},
|
|
4886
5222
|
},
|
|
5223
|
+
evaluatePasskeyPrompt: {
|
|
5224
|
+
always: [
|
|
5225
|
+
{
|
|
5226
|
+
cond: 'shouldPromptPasskeyRegistration',
|
|
5227
|
+
target: '#signInActor.passkeyPrompt',
|
|
5228
|
+
},
|
|
5229
|
+
{
|
|
5230
|
+
cond: 'shouldVerifyAttribute',
|
|
5231
|
+
actions: [
|
|
5232
|
+
'setShouldVerifyUserAttributeStep',
|
|
5233
|
+
'setUnverifiedUserAttributes',
|
|
5234
|
+
],
|
|
5235
|
+
target: '#signInActor.resolved',
|
|
5236
|
+
},
|
|
5237
|
+
{
|
|
5238
|
+
actions: 'setConfirmAttributeCompleteStep',
|
|
5239
|
+
target: '#signInActor.resolved',
|
|
5240
|
+
},
|
|
5241
|
+
],
|
|
5242
|
+
},
|
|
4887
5243
|
resendSignUpCode: {
|
|
4888
5244
|
invoke: {
|
|
4889
5245
|
src: 'handleResendSignUpCode',
|
|
@@ -4918,23 +5274,70 @@ function signInActor({ services }) {
|
|
|
4918
5274
|
on: {
|
|
4919
5275
|
CHANGE: { actions: 'handleInput' },
|
|
4920
5276
|
FEDERATED_SIGN_IN: { target: '#signInActor.federatedSignIn' },
|
|
4921
|
-
|
|
5277
|
+
SHOW_AUTH_METHODS: {
|
|
5278
|
+
actions: 'setUsernameSignIn',
|
|
5279
|
+
target: 'selectMethod',
|
|
5280
|
+
},
|
|
5281
|
+
SUBMIT: [
|
|
5282
|
+
{
|
|
5283
|
+
cond: 'shouldSelectAuthMethod',
|
|
5284
|
+
actions: 'handleSubmit',
|
|
5285
|
+
target: 'selectMethod',
|
|
5286
|
+
},
|
|
5287
|
+
{
|
|
5288
|
+
actions: 'handleSubmit',
|
|
5289
|
+
target: 'submit',
|
|
5290
|
+
},
|
|
5291
|
+
],
|
|
5292
|
+
},
|
|
5293
|
+
},
|
|
5294
|
+
selectMethod: {
|
|
5295
|
+
entry: [
|
|
5296
|
+
'sendUpdate',
|
|
5297
|
+
'setSelectAuthMethodStep',
|
|
5298
|
+
'setUsernameSignIn',
|
|
5299
|
+
],
|
|
5300
|
+
on: {
|
|
5301
|
+
SELECT_METHOD: {
|
|
5302
|
+
actions: 'setSelectedAuthMethod',
|
|
5303
|
+
target: 'submit',
|
|
5304
|
+
},
|
|
5305
|
+
SUBMIT: {
|
|
5306
|
+
actions: ['handleSubmit', 'setSelectedAuthMethodFromForm'],
|
|
5307
|
+
target: 'submit',
|
|
5308
|
+
},
|
|
5309
|
+
SIGN_IN: {
|
|
5310
|
+
target: 'edit',
|
|
5311
|
+
},
|
|
4922
5312
|
},
|
|
4923
5313
|
},
|
|
4924
5314
|
submit: {
|
|
4925
5315
|
tags: 'pending',
|
|
4926
5316
|
entry: ['clearError', 'sendUpdate', 'setUsernameSignIn'],
|
|
4927
5317
|
exit: 'clearFormValues',
|
|
4928
|
-
invoke: {
|
|
5318
|
+
invoke: {
|
|
5319
|
+
src: 'handleSignIn',
|
|
5320
|
+
onDone: handleSignInResponse.onDone,
|
|
5321
|
+
onError: [
|
|
5322
|
+
{
|
|
5323
|
+
cond: 'shouldReturnToSelectMethod',
|
|
5324
|
+
actions: 'setRemoteError',
|
|
5325
|
+
target: 'selectMethod',
|
|
5326
|
+
},
|
|
5327
|
+
handleSignInResponse.onError,
|
|
5328
|
+
],
|
|
5329
|
+
},
|
|
4929
5330
|
},
|
|
4930
5331
|
},
|
|
4931
5332
|
},
|
|
4932
|
-
confirmSignIn:
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
5333
|
+
confirmSignIn: {
|
|
5334
|
+
...getDefaultConfirmSignInState([
|
|
5335
|
+
'clearChallengeName',
|
|
5336
|
+
'clearFormValues',
|
|
5337
|
+
'clearError',
|
|
5338
|
+
'clearTouched',
|
|
5339
|
+
]),
|
|
5340
|
+
},
|
|
4938
5341
|
forceChangePassword: {
|
|
4939
5342
|
entry: 'sendUpdate',
|
|
4940
5343
|
type: 'parallel',
|
|
@@ -5007,21 +5410,40 @@ function signInActor({ services }) {
|
|
|
5007
5410
|
},
|
|
5008
5411
|
},
|
|
5009
5412
|
},
|
|
5010
|
-
setupTotp:
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5413
|
+
setupTotp: {
|
|
5414
|
+
...getDefaultConfirmSignInState([
|
|
5415
|
+
'clearFormValues',
|
|
5416
|
+
'clearError',
|
|
5417
|
+
'clearTouched',
|
|
5418
|
+
]),
|
|
5419
|
+
},
|
|
5420
|
+
setupEmail: {
|
|
5421
|
+
...getDefaultConfirmSignInState([
|
|
5422
|
+
'clearFormValues',
|
|
5423
|
+
'clearError',
|
|
5424
|
+
'clearTouched',
|
|
5425
|
+
]),
|
|
5426
|
+
},
|
|
5427
|
+
selectMfaType: {
|
|
5428
|
+
...getDefaultConfirmSignInState([
|
|
5429
|
+
'clearFormValues',
|
|
5430
|
+
'clearError',
|
|
5431
|
+
'clearTouched',
|
|
5432
|
+
]),
|
|
5433
|
+
},
|
|
5434
|
+
passkeyPrompt: {
|
|
5435
|
+
entry: 'sendUpdate',
|
|
5436
|
+
on: {
|
|
5437
|
+
SUBMIT: {
|
|
5438
|
+
actions: 'setConfirmAttributeCompleteStep',
|
|
5439
|
+
target: 'resolved',
|
|
5440
|
+
},
|
|
5441
|
+
SKIP: {
|
|
5442
|
+
actions: 'setConfirmAttributeCompleteStep',
|
|
5443
|
+
target: 'resolved',
|
|
5444
|
+
},
|
|
5445
|
+
},
|
|
5446
|
+
},
|
|
5025
5447
|
resolved: {
|
|
5026
5448
|
type: 'final',
|
|
5027
5449
|
data: (context) => ({
|
|
@@ -5047,9 +5469,41 @@ function signInActor({ services }) {
|
|
|
5047
5469
|
handleResendSignUpCode({ username }) {
|
|
5048
5470
|
return services.handleResendSignUpCode({ username });
|
|
5049
5471
|
},
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5472
|
+
resendSignInCode({ username, selectedAuthMethod, availableAuthMethods, preferredChallenge, }) {
|
|
5473
|
+
// Resend code by calling signIn again with the same parameters
|
|
5474
|
+
const method = selectedAuthMethod ??
|
|
5475
|
+
preferredChallenge ??
|
|
5476
|
+
availableAuthMethods?.[0] ??
|
|
5477
|
+
'PASSWORD';
|
|
5478
|
+
return services.handleSignIn({
|
|
5479
|
+
username,
|
|
5480
|
+
options: {
|
|
5481
|
+
authFlowType: 'USER_AUTH',
|
|
5482
|
+
preferredChallenge: method,
|
|
5483
|
+
},
|
|
5484
|
+
});
|
|
5485
|
+
},
|
|
5486
|
+
handleSignIn({ formValues, username, selectedAuthMethod, availableAuthMethods, preferredChallenge, }) {
|
|
5487
|
+
// Determine which method to use
|
|
5488
|
+
const method = selectedAuthMethod ??
|
|
5489
|
+
preferredChallenge ??
|
|
5490
|
+
availableAuthMethods?.[0] ??
|
|
5491
|
+
'PASSWORD';
|
|
5492
|
+
if (method === 'PASSWORD') {
|
|
5493
|
+
// Traditional password flow
|
|
5494
|
+
const { password } = formValues;
|
|
5495
|
+
return services.handleSignIn({ username, password });
|
|
5496
|
+
}
|
|
5497
|
+
else {
|
|
5498
|
+
// Passwordless flow using USER_AUTH
|
|
5499
|
+
return services.handleSignIn({
|
|
5500
|
+
username,
|
|
5501
|
+
options: {
|
|
5502
|
+
authFlowType: 'USER_AUTH',
|
|
5503
|
+
preferredChallenge: method,
|
|
5504
|
+
},
|
|
5505
|
+
});
|
|
5506
|
+
}
|
|
5053
5507
|
},
|
|
5054
5508
|
confirmSignIn({ formValues, step }) {
|
|
5055
5509
|
const formValuesKey = getConfirmSignInFormValuesKey(step);
|
|
@@ -5133,26 +5587,6 @@ const handleAutoSignInResponse = {
|
|
|
5133
5587
|
target: '#signUpActor.resolved',
|
|
5134
5588
|
},
|
|
5135
5589
|
};
|
|
5136
|
-
const handleFetchUserAttributesResponse = {
|
|
5137
|
-
onDone: [
|
|
5138
|
-
{
|
|
5139
|
-
cond: 'shouldVerifyAttribute',
|
|
5140
|
-
actions: [
|
|
5141
|
-
'setShouldVerifyUserAttributeStep',
|
|
5142
|
-
'setUnverifiedUserAttributes',
|
|
5143
|
-
],
|
|
5144
|
-
target: '#signUpActor.resolved',
|
|
5145
|
-
},
|
|
5146
|
-
{
|
|
5147
|
-
actions: 'setConfirmAttributeCompleteStep',
|
|
5148
|
-
target: '#signUpActor.resolved',
|
|
5149
|
-
},
|
|
5150
|
-
],
|
|
5151
|
-
onError: {
|
|
5152
|
-
actions: 'setConfirmAttributeCompleteStep',
|
|
5153
|
-
target: '#signUpActor.resolved',
|
|
5154
|
-
},
|
|
5155
|
-
};
|
|
5156
5590
|
function signUpActor({ services }) {
|
|
5157
5591
|
return xstate.createMachine({
|
|
5158
5592
|
id: 'signUpActor',
|
|
@@ -5172,10 +5606,65 @@ function signUpActor({ services }) {
|
|
|
5172
5606
|
fetchUserAttributes: {
|
|
5173
5607
|
invoke: {
|
|
5174
5608
|
src: 'fetchUserAttributes',
|
|
5175
|
-
|
|
5609
|
+
onDone: [
|
|
5610
|
+
{
|
|
5611
|
+
cond: 'hasPasskeyRegistrationPrompts',
|
|
5612
|
+
actions: 'setFetchedUserAttributes',
|
|
5613
|
+
target: 'checkPasskeys',
|
|
5614
|
+
},
|
|
5615
|
+
{
|
|
5616
|
+
actions: 'setFetchedUserAttributes',
|
|
5617
|
+
target: 'evaluatePasskeyPrompt',
|
|
5618
|
+
},
|
|
5619
|
+
],
|
|
5620
|
+
onError: {
|
|
5621
|
+
actions: 'setConfirmAttributeCompleteStep',
|
|
5622
|
+
target: '#signUpActor.resolved',
|
|
5623
|
+
},
|
|
5624
|
+
},
|
|
5625
|
+
},
|
|
5626
|
+
checkPasskeys: {
|
|
5627
|
+
invoke: {
|
|
5628
|
+
src: async () => {
|
|
5629
|
+
try {
|
|
5630
|
+
const result = await auth.listWebAuthnCredentials();
|
|
5631
|
+
return result.credentials && result.credentials.length > 0;
|
|
5632
|
+
}
|
|
5633
|
+
catch {
|
|
5634
|
+
return false;
|
|
5635
|
+
}
|
|
5636
|
+
},
|
|
5637
|
+
onDone: {
|
|
5638
|
+
actions: 'setHasExistingPasskeys',
|
|
5639
|
+
target: 'evaluatePasskeyPrompt',
|
|
5640
|
+
},
|
|
5641
|
+
onError: {
|
|
5642
|
+
actions: 'clearHasExistingPasskeys',
|
|
5643
|
+
target: 'evaluatePasskeyPrompt',
|
|
5644
|
+
},
|
|
5176
5645
|
},
|
|
5177
5646
|
},
|
|
5178
|
-
|
|
5647
|
+
evaluatePasskeyPrompt: {
|
|
5648
|
+
always: [
|
|
5649
|
+
{
|
|
5650
|
+
cond: 'shouldPromptPasskeyRegistrationAfterSignup',
|
|
5651
|
+
target: '#signUpActor.passkeyPrompt',
|
|
5652
|
+
},
|
|
5653
|
+
{
|
|
5654
|
+
cond: 'shouldVerifyAttribute',
|
|
5655
|
+
actions: [
|
|
5656
|
+
'setShouldVerifyUserAttributeStep',
|
|
5657
|
+
'setUnverifiedUserAttributes',
|
|
5658
|
+
],
|
|
5659
|
+
target: '#signUpActor.resolved',
|
|
5660
|
+
},
|
|
5661
|
+
{
|
|
5662
|
+
actions: 'setConfirmAttributeCompleteStep',
|
|
5663
|
+
target: '#signUpActor.resolved',
|
|
5664
|
+
},
|
|
5665
|
+
],
|
|
5666
|
+
},
|
|
5667
|
+
federatedSignIn: { ...getFederatedSignInState('signUp') },
|
|
5179
5668
|
resetPassword: {
|
|
5180
5669
|
invoke: { src: 'resetPassword', ...handleResetPasswordResponse },
|
|
5181
5670
|
},
|
|
@@ -5194,7 +5683,10 @@ function signUpActor({ services }) {
|
|
|
5194
5683
|
cond: 'isUserAlreadyConfirmed',
|
|
5195
5684
|
target: '#signUpActor.resolved',
|
|
5196
5685
|
},
|
|
5197
|
-
{
|
|
5686
|
+
{
|
|
5687
|
+
actions: ['setRemoteError', 'sendUpdate'],
|
|
5688
|
+
target: '#signUpActor.confirmSignUp',
|
|
5689
|
+
},
|
|
5198
5690
|
],
|
|
5199
5691
|
},
|
|
5200
5692
|
},
|
|
@@ -5232,7 +5724,13 @@ function signUpActor({ services }) {
|
|
|
5232
5724
|
idle: {
|
|
5233
5725
|
entry: ['sendUpdate'],
|
|
5234
5726
|
on: {
|
|
5235
|
-
SUBMIT: {
|
|
5727
|
+
SUBMIT: {
|
|
5728
|
+
actions: [
|
|
5729
|
+
'setSelectedAuthMethodFromForm',
|
|
5730
|
+
'handleSubmit',
|
|
5731
|
+
],
|
|
5732
|
+
target: 'validate',
|
|
5733
|
+
},
|
|
5236
5734
|
},
|
|
5237
5735
|
},
|
|
5238
5736
|
validate: {
|
|
@@ -5317,6 +5815,13 @@ function signUpActor({ services }) {
|
|
|
5317
5815
|
},
|
|
5318
5816
|
},
|
|
5319
5817
|
},
|
|
5818
|
+
passkeyPrompt: {
|
|
5819
|
+
entry: 'sendUpdate',
|
|
5820
|
+
on: {
|
|
5821
|
+
SKIP: { target: 'resolved' },
|
|
5822
|
+
SUBMIT: { target: 'resolved' },
|
|
5823
|
+
},
|
|
5824
|
+
},
|
|
5320
5825
|
resolved: {
|
|
5321
5826
|
type: 'final',
|
|
5322
5827
|
data: (context) => ({
|
|
@@ -5354,9 +5859,10 @@ function signUpActor({ services }) {
|
|
|
5354
5859
|
return auth.signInWithRedirect(data);
|
|
5355
5860
|
},
|
|
5356
5861
|
handleSignUp(context) {
|
|
5357
|
-
const { formValues, loginMechanisms, username } = context;
|
|
5862
|
+
const { formValues, loginMechanisms, username, selectedAuthMethod, preferredChallenge, } = context;
|
|
5358
5863
|
const loginMechanism = loginMechanisms[0];
|
|
5359
|
-
const
|
|
5864
|
+
const authMethod = selectedAuthMethod ?? preferredChallenge;
|
|
5865
|
+
const input = getSignUpInput(username, formValues, loginMechanism, authMethod);
|
|
5360
5866
|
return services.handleSignUp(input);
|
|
5361
5867
|
},
|
|
5362
5868
|
async validateSignUp(context) {
|
|
@@ -5367,6 +5873,8 @@ function signUpActor({ services }) {
|
|
|
5367
5873
|
// Validation for default form fields
|
|
5368
5874
|
services.validateConfirmPassword,
|
|
5369
5875
|
services.validatePreferredUsername,
|
|
5876
|
+
// Validation for required fields based on auth method
|
|
5877
|
+
services.validateRequiredFieldsForAuthMethod,
|
|
5370
5878
|
// Validation for any custom Sign Up fields
|
|
5371
5879
|
services.validateCustomSignUp,
|
|
5372
5880
|
]);
|
|
@@ -5498,20 +6006,29 @@ function verifyUserAttributesActor() {
|
|
|
5498
6006
|
});
|
|
5499
6007
|
}
|
|
5500
6008
|
|
|
5501
|
-
const getActorContext = (context, defaultStep) =>
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
6009
|
+
const getActorContext = (context, defaultStep) => {
|
|
6010
|
+
const availableAuthMethods = getAvailableAuthMethods(context.passwordlessCapabilities, context.config?.passwordless?.hiddenAuthMethods);
|
|
6011
|
+
// Determine effective preferred challenge: component prop takes precedence over backend config
|
|
6012
|
+
const preferredChallenge = context.config?.passwordless?.preferredAuthMethod ??
|
|
6013
|
+
context.passwordlessCapabilities?.preferredChallenge;
|
|
6014
|
+
return {
|
|
6015
|
+
...context.actorDoneData,
|
|
6016
|
+
step: context?.actorDoneData?.step ?? defaultStep,
|
|
6017
|
+
// initialize empty objects on actor start
|
|
6018
|
+
formValues: {},
|
|
6019
|
+
touched: {},
|
|
6020
|
+
validationError: {},
|
|
6021
|
+
// values included on `context.config` that should be available in actors
|
|
6022
|
+
formFields: context.config?.formFields,
|
|
6023
|
+
loginMechanisms: context.config?.loginMechanisms,
|
|
6024
|
+
passwordSettings: context.config?.passwordSettings,
|
|
6025
|
+
signUpAttributes: context.config?.signUpAttributes,
|
|
6026
|
+
socialProviders: context.config?.socialProviders,
|
|
6027
|
+
availableAuthMethods,
|
|
6028
|
+
preferredChallenge,
|
|
6029
|
+
passwordless: context.config?.passwordless,
|
|
6030
|
+
};
|
|
6031
|
+
};
|
|
5515
6032
|
const { choose, stop } = xstate.actions;
|
|
5516
6033
|
const stopActor = (machineId) => stop(machineId);
|
|
5517
6034
|
// setup step waits for ui to emit INIT action to proceed to configure
|
|
@@ -5609,6 +6126,8 @@ function createAuthenticatorMachine(options) {
|
|
|
5609
6126
|
},
|
|
5610
6127
|
on: {
|
|
5611
6128
|
FORGOT_PASSWORD: 'forgotPasswordActor',
|
|
6129
|
+
SELECT_METHOD: { actions: 'forwardToActor' },
|
|
6130
|
+
SHOW_AUTH_METHODS: { actions: 'forwardToActor' },
|
|
5612
6131
|
SIGN_IN: 'signInActor',
|
|
5613
6132
|
SIGN_UP: 'signUpActor',
|
|
5614
6133
|
'done.invoke.signInActor': [
|
|
@@ -5775,10 +6294,11 @@ function createAuthenticatorMachine(options) {
|
|
|
5775
6294
|
}),
|
|
5776
6295
|
}),
|
|
5777
6296
|
applyAmplifyConfig: xstate.assign({
|
|
6297
|
+
passwordlessCapabilities: (_, { data: cliConfig }) => cliConfig.passwordlessCapabilities,
|
|
5778
6298
|
config(context, { data: cliConfig }) {
|
|
5779
6299
|
// Prefer explicitly configured settings over default CLI values\
|
|
5780
6300
|
const { loginMechanisms = cliConfig.loginMechanisms ?? [], signUpAttributes = cliConfig.signUpAttributes ?? [], socialProviders = cliConfig.socialProviders ?? [], initialState, formFields: _formFields, passwordSettings = cliConfig.passwordFormat ??
|
|
5781
|
-
{}, } = context.config;
|
|
6301
|
+
{}, passwordless, } = context.config;
|
|
5782
6302
|
// By default, Cognito assumes `username`, so there isn't a different username attribute like `email`.
|
|
5783
6303
|
// We explicitly add it as a login mechanism to be consistent with Admin UI's language.
|
|
5784
6304
|
if (loginMechanisms.length === 0) {
|
|
@@ -5790,6 +6310,7 @@ function createAuthenticatorMachine(options) {
|
|
|
5790
6310
|
initialState,
|
|
5791
6311
|
loginMechanisms,
|
|
5792
6312
|
passwordSettings,
|
|
6313
|
+
passwordless,
|
|
5793
6314
|
signUpAttributes,
|
|
5794
6315
|
socialProviders,
|
|
5795
6316
|
};
|