@aws-amplify/ui 6.13.0 → 6.15.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 +58 -6
- package/dist/index.js +625 -111
- package/dist/styles/StorageBrowser.css +0 -1
- package/dist/styles/StorageBrowser.layer.css +0 -1
- package/dist/styles/authenticator.css +17 -0
- package/dist/styles/authenticator.layer.css +17 -0
- package/dist/styles/modal.css +81 -0
- package/dist/styles/modal.layer.css +83 -0
- package/dist/styles.css +100 -1
- package/dist/styles.layer.css +100 -1
- 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/dist/types/theme/components/index.d.ts +3 -1
- package/dist/types/theme/components/modal.d.ts +10 -0
- 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,21 +4264,44 @@ 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
|
+
}
|
|
4180
4305
|
// When 'username' is in loginMechanisms, always use the username field for the Username parameter.
|
|
4181
4306
|
// This handles both username-only mode and alias mode (username + email/phone as sign-in options).
|
|
4182
4307
|
// See: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-aliases
|
|
@@ -4191,13 +4316,47 @@ const getUsernameSignUp = ({ formValues, loginMechanisms, }) => {
|
|
|
4191
4316
|
// Otherwise, use the primary login mechanism (email as username)
|
|
4192
4317
|
return formValues[loginMechanism];
|
|
4193
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
|
+
};
|
|
4194
4348
|
|
|
4195
4349
|
const { assign } = xstate.actions;
|
|
4196
4350
|
const clearActorDoneData = assign({ actorDoneData: undefined });
|
|
4197
4351
|
const clearChallengeName = assign({ challengeName: undefined });
|
|
4198
4352
|
const clearMissingAttributes = assign({ missingAttributes: undefined });
|
|
4199
4353
|
const clearError = assign({ remoteError: undefined });
|
|
4200
|
-
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
|
+
});
|
|
4201
4360
|
const clearTouched = assign({ touched: {} });
|
|
4202
4361
|
const clearUser = assign({ user: undefined });
|
|
4203
4362
|
const clearValidationError = assign({ validationError: {} });
|
|
@@ -4298,7 +4457,28 @@ const setRemoteError = assign({
|
|
|
4298
4457
|
if (data.name === 'NoUserPoolError') {
|
|
4299
4458
|
return `Configuration error (see console) – please contact the administrator`;
|
|
4300
4459
|
}
|
|
4301
|
-
|
|
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;
|
|
4302
4482
|
},
|
|
4303
4483
|
});
|
|
4304
4484
|
const setUser = assign({ user: (_, { data }) => data });
|
|
@@ -4335,8 +4515,12 @@ const handleBlur = assign({
|
|
|
4335
4515
|
}),
|
|
4336
4516
|
});
|
|
4337
4517
|
const setUnverifiedUserAttributes = assign({
|
|
4338
|
-
unverifiedUserAttributes: (
|
|
4339
|
-
|
|
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;
|
|
4340
4524
|
const unverifiedUserAttributes = {
|
|
4341
4525
|
...(email && { email }),
|
|
4342
4526
|
...(phone_number && { phone_number }),
|
|
@@ -4350,11 +4534,34 @@ const setSelectedUserAttribute = assign({
|
|
|
4350
4534
|
});
|
|
4351
4535
|
// Maps to unexposed `ConfirmSignUpSignUpStep`
|
|
4352
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
|
+
});
|
|
4353
4559
|
const ACTIONS = {
|
|
4354
4560
|
clearActorDoneData,
|
|
4355
4561
|
clearChallengeName,
|
|
4356
4562
|
clearError,
|
|
4357
4563
|
clearFormValues,
|
|
4564
|
+
clearHasExistingPasskeys,
|
|
4358
4565
|
clearMissingAttributes,
|
|
4359
4566
|
clearSelectedUserAttribute,
|
|
4360
4567
|
clearTouched,
|
|
@@ -4366,7 +4573,9 @@ const ACTIONS = {
|
|
|
4366
4573
|
setAllowedMfaTypes,
|
|
4367
4574
|
setChallengeName,
|
|
4368
4575
|
setCodeDeliveryDetails,
|
|
4576
|
+
setFetchedUserAttributes,
|
|
4369
4577
|
setFieldErrors,
|
|
4578
|
+
setHasExistingPasskeys,
|
|
4370
4579
|
setMissingAttributes,
|
|
4371
4580
|
setNextResetPasswordStep,
|
|
4372
4581
|
setNextSignInStep,
|
|
@@ -4374,6 +4583,9 @@ const ACTIONS = {
|
|
|
4374
4583
|
setRemoteError,
|
|
4375
4584
|
setConfirmAttributeCompleteStep,
|
|
4376
4585
|
setConfirmSignUpSignUpStep,
|
|
4586
|
+
setSelectAuthMethodStep,
|
|
4587
|
+
setSelectedAuthMethod,
|
|
4588
|
+
setSelectedAuthMethodFromForm,
|
|
4377
4589
|
setShouldVerifyUserAttributeStep,
|
|
4378
4590
|
setSelectedUserAttribute,
|
|
4379
4591
|
setSignInStep,
|
|
@@ -4417,7 +4629,11 @@ const shouldResetPassword = ({ step }) => step === 'RESET_PASSWORD';
|
|
|
4417
4629
|
const shouldConfirmResetPassword = ({ step }) => step === 'CONFIRM_RESET_PASSWORD_WITH_CODE';
|
|
4418
4630
|
const shouldConfirmSignUp = ({ step }) => step === 'CONFIRM_SIGN_UP';
|
|
4419
4631
|
// miscellaneous guards
|
|
4420
|
-
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;
|
|
4421
4637
|
const { email, phone_number, phone_number_verified, email_verified } = data;
|
|
4422
4638
|
// if neither email nor phone_number exist
|
|
4423
4639
|
// there is nothing to verify
|
|
@@ -4442,11 +4658,51 @@ const shouldVerifyAttribute = (_, { data }) => {
|
|
|
4442
4658
|
* https://github.com/aws-amplify/amplify-ui/issues/219
|
|
4443
4659
|
*/
|
|
4444
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';
|
|
4445
4700
|
const GUARDS = {
|
|
4446
4701
|
hasCompletedAttributeConfirmation,
|
|
4447
4702
|
hasCompletedResetPassword,
|
|
4448
4703
|
hasCompletedSignIn,
|
|
4449
4704
|
hasCompletedSignUp,
|
|
4705
|
+
hasPasskeyRegistrationPrompts,
|
|
4450
4706
|
isConfirmSignUpStep,
|
|
4451
4707
|
isConfirmUserAttributeStep,
|
|
4452
4708
|
isResetPasswordStep,
|
|
@@ -4460,10 +4716,14 @@ const GUARDS = {
|
|
|
4460
4716
|
shouldConfirmSignUpFromSignIn,
|
|
4461
4717
|
shouldResetPassword,
|
|
4462
4718
|
shouldResetPasswordFromSignIn,
|
|
4719
|
+
shouldReturnToSelectMethod,
|
|
4720
|
+
shouldSelectAuthMethod,
|
|
4463
4721
|
shouldSetupTotp,
|
|
4464
4722
|
shouldSetupEmail,
|
|
4465
4723
|
shouldSelectMfaType,
|
|
4466
4724
|
shouldVerifyAttribute,
|
|
4725
|
+
shouldPromptPasskeyRegistration,
|
|
4726
|
+
shouldPromptPasskeyRegistrationAfterSignup,
|
|
4467
4727
|
};
|
|
4468
4728
|
|
|
4469
4729
|
// Runs all validators given. Resolves if there are no error. Rejects otherwise.
|
|
@@ -4511,11 +4771,24 @@ const defaultServices = {
|
|
|
4511
4771
|
const parsedSocialProviders = loginWith?.oauth?.providers
|
|
4512
4772
|
? loginWith.oauth.providers?.map((provider) => provider.toString().toLowerCase())
|
|
4513
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
|
+
};
|
|
4514
4786
|
return {
|
|
4515
4787
|
...cliConfig,
|
|
4516
4788
|
loginMechanisms: parsedLoginMechanisms,
|
|
4517
4789
|
signUpAttributes: parsedSignupAttributes,
|
|
4518
4790
|
socialProviders: parsedSocialProviders,
|
|
4791
|
+
passwordlessCapabilities,
|
|
4519
4792
|
};
|
|
4520
4793
|
},
|
|
4521
4794
|
getCurrentUser: auth.getCurrentUser,
|
|
@@ -4578,6 +4851,30 @@ const defaultServices = {
|
|
|
4578
4851
|
}
|
|
4579
4852
|
},
|
|
4580
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
|
+
},
|
|
4581
4878
|
};
|
|
4582
4879
|
|
|
4583
4880
|
function forgotPasswordActor({ services, }) {
|
|
@@ -4807,32 +5104,13 @@ const handleSignInResponse = {
|
|
|
4807
5104
|
'setNextSignInStep',
|
|
4808
5105
|
'setTotpSecretCode',
|
|
4809
5106
|
'setAllowedMfaTypes',
|
|
5107
|
+
'setCodeDeliveryDetails',
|
|
4810
5108
|
],
|
|
4811
5109
|
target: '#signInActor.init',
|
|
4812
5110
|
},
|
|
4813
5111
|
],
|
|
4814
5112
|
onError: { actions: 'setRemoteError', target: 'edit' },
|
|
4815
5113
|
};
|
|
4816
|
-
const handleFetchUserAttributesResponse$1 = {
|
|
4817
|
-
onDone: [
|
|
4818
|
-
{
|
|
4819
|
-
cond: 'shouldVerifyAttribute',
|
|
4820
|
-
actions: [
|
|
4821
|
-
'setShouldVerifyUserAttributeStep',
|
|
4822
|
-
'setUnverifiedUserAttributes',
|
|
4823
|
-
],
|
|
4824
|
-
target: '#signInActor.resolved',
|
|
4825
|
-
},
|
|
4826
|
-
{
|
|
4827
|
-
actions: 'setConfirmAttributeCompleteStep',
|
|
4828
|
-
target: '#signInActor.resolved',
|
|
4829
|
-
},
|
|
4830
|
-
],
|
|
4831
|
-
onError: {
|
|
4832
|
-
actions: 'setConfirmAttributeCompleteStep',
|
|
4833
|
-
target: '#signInActor.resolved',
|
|
4834
|
-
},
|
|
4835
|
-
};
|
|
4836
5114
|
const getDefaultConfirmSignInState = (exit) => ({
|
|
4837
5115
|
initial: 'edit',
|
|
4838
5116
|
exit,
|
|
@@ -4843,6 +5121,7 @@ const getDefaultConfirmSignInState = (exit) => ({
|
|
|
4843
5121
|
SUBMIT: { actions: 'handleSubmit', target: 'submit' },
|
|
4844
5122
|
SIGN_IN: '#signInActor.signIn',
|
|
4845
5123
|
CHANGE: { actions: 'handleInput' },
|
|
5124
|
+
RESEND: { target: 'resend' },
|
|
4846
5125
|
},
|
|
4847
5126
|
},
|
|
4848
5127
|
submit: {
|
|
@@ -4850,6 +5129,21 @@ const getDefaultConfirmSignInState = (exit) => ({
|
|
|
4850
5129
|
entry: ['sendUpdate', 'clearError'],
|
|
4851
5130
|
invoke: { src: 'confirmSignIn', ...handleSignInResponse },
|
|
4852
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
|
+
},
|
|
4853
5147
|
},
|
|
4854
5148
|
});
|
|
4855
5149
|
function signInActor({ services }) {
|
|
@@ -4884,13 +5178,68 @@ function signInActor({ services }) {
|
|
|
4884
5178
|
{ target: 'signIn' },
|
|
4885
5179
|
],
|
|
4886
5180
|
},
|
|
4887
|
-
federatedSignIn: getFederatedSignInState('signIn'),
|
|
5181
|
+
federatedSignIn: { ...getFederatedSignInState('signIn') },
|
|
4888
5182
|
fetchUserAttributes: {
|
|
4889
5183
|
invoke: {
|
|
4890
5184
|
src: 'fetchUserAttributes',
|
|
4891
|
-
|
|
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
|
+
},
|
|
4892
5221
|
},
|
|
4893
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
|
+
},
|
|
4894
5243
|
resendSignUpCode: {
|
|
4895
5244
|
invoke: {
|
|
4896
5245
|
src: 'handleResendSignUpCode',
|
|
@@ -4925,23 +5274,70 @@ function signInActor({ services }) {
|
|
|
4925
5274
|
on: {
|
|
4926
5275
|
CHANGE: { actions: 'handleInput' },
|
|
4927
5276
|
FEDERATED_SIGN_IN: { target: '#signInActor.federatedSignIn' },
|
|
4928
|
-
|
|
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
|
+
},
|
|
4929
5312
|
},
|
|
4930
5313
|
},
|
|
4931
5314
|
submit: {
|
|
4932
5315
|
tags: 'pending',
|
|
4933
5316
|
entry: ['clearError', 'sendUpdate', 'setUsernameSignIn'],
|
|
4934
5317
|
exit: 'clearFormValues',
|
|
4935
|
-
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
|
+
},
|
|
4936
5330
|
},
|
|
4937
5331
|
},
|
|
4938
5332
|
},
|
|
4939
|
-
confirmSignIn:
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
5333
|
+
confirmSignIn: {
|
|
5334
|
+
...getDefaultConfirmSignInState([
|
|
5335
|
+
'clearChallengeName',
|
|
5336
|
+
'clearFormValues',
|
|
5337
|
+
'clearError',
|
|
5338
|
+
'clearTouched',
|
|
5339
|
+
]),
|
|
5340
|
+
},
|
|
4945
5341
|
forceChangePassword: {
|
|
4946
5342
|
entry: 'sendUpdate',
|
|
4947
5343
|
type: 'parallel',
|
|
@@ -5014,21 +5410,40 @@ function signInActor({ services }) {
|
|
|
5014
5410
|
},
|
|
5015
5411
|
},
|
|
5016
5412
|
},
|
|
5017
|
-
setupTotp:
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
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
|
+
},
|
|
5032
5447
|
resolved: {
|
|
5033
5448
|
type: 'final',
|
|
5034
5449
|
data: (context) => ({
|
|
@@ -5054,9 +5469,41 @@ function signInActor({ services }) {
|
|
|
5054
5469
|
handleResendSignUpCode({ username }) {
|
|
5055
5470
|
return services.handleResendSignUpCode({ username });
|
|
5056
5471
|
},
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
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
|
+
}
|
|
5060
5507
|
},
|
|
5061
5508
|
confirmSignIn({ formValues, step }) {
|
|
5062
5509
|
const formValuesKey = getConfirmSignInFormValuesKey(step);
|
|
@@ -5140,26 +5587,6 @@ const handleAutoSignInResponse = {
|
|
|
5140
5587
|
target: '#signUpActor.resolved',
|
|
5141
5588
|
},
|
|
5142
5589
|
};
|
|
5143
|
-
const handleFetchUserAttributesResponse = {
|
|
5144
|
-
onDone: [
|
|
5145
|
-
{
|
|
5146
|
-
cond: 'shouldVerifyAttribute',
|
|
5147
|
-
actions: [
|
|
5148
|
-
'setShouldVerifyUserAttributeStep',
|
|
5149
|
-
'setUnverifiedUserAttributes',
|
|
5150
|
-
],
|
|
5151
|
-
target: '#signUpActor.resolved',
|
|
5152
|
-
},
|
|
5153
|
-
{
|
|
5154
|
-
actions: 'setConfirmAttributeCompleteStep',
|
|
5155
|
-
target: '#signUpActor.resolved',
|
|
5156
|
-
},
|
|
5157
|
-
],
|
|
5158
|
-
onError: {
|
|
5159
|
-
actions: 'setConfirmAttributeCompleteStep',
|
|
5160
|
-
target: '#signUpActor.resolved',
|
|
5161
|
-
},
|
|
5162
|
-
};
|
|
5163
5590
|
function signUpActor({ services }) {
|
|
5164
5591
|
return xstate.createMachine({
|
|
5165
5592
|
id: 'signUpActor',
|
|
@@ -5179,10 +5606,65 @@ function signUpActor({ services }) {
|
|
|
5179
5606
|
fetchUserAttributes: {
|
|
5180
5607
|
invoke: {
|
|
5181
5608
|
src: 'fetchUserAttributes',
|
|
5182
|
-
|
|
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
|
+
},
|
|
5183
5645
|
},
|
|
5184
5646
|
},
|
|
5185
|
-
|
|
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') },
|
|
5186
5668
|
resetPassword: {
|
|
5187
5669
|
invoke: { src: 'resetPassword', ...handleResetPasswordResponse },
|
|
5188
5670
|
},
|
|
@@ -5201,7 +5683,10 @@ function signUpActor({ services }) {
|
|
|
5201
5683
|
cond: 'isUserAlreadyConfirmed',
|
|
5202
5684
|
target: '#signUpActor.resolved',
|
|
5203
5685
|
},
|
|
5204
|
-
{
|
|
5686
|
+
{
|
|
5687
|
+
actions: ['setRemoteError', 'sendUpdate'],
|
|
5688
|
+
target: '#signUpActor.confirmSignUp',
|
|
5689
|
+
},
|
|
5205
5690
|
],
|
|
5206
5691
|
},
|
|
5207
5692
|
},
|
|
@@ -5239,7 +5724,13 @@ function signUpActor({ services }) {
|
|
|
5239
5724
|
idle: {
|
|
5240
5725
|
entry: ['sendUpdate'],
|
|
5241
5726
|
on: {
|
|
5242
|
-
SUBMIT: {
|
|
5727
|
+
SUBMIT: {
|
|
5728
|
+
actions: [
|
|
5729
|
+
'setSelectedAuthMethodFromForm',
|
|
5730
|
+
'handleSubmit',
|
|
5731
|
+
],
|
|
5732
|
+
target: 'validate',
|
|
5733
|
+
},
|
|
5243
5734
|
},
|
|
5244
5735
|
},
|
|
5245
5736
|
validate: {
|
|
@@ -5324,6 +5815,13 @@ function signUpActor({ services }) {
|
|
|
5324
5815
|
},
|
|
5325
5816
|
},
|
|
5326
5817
|
},
|
|
5818
|
+
passkeyPrompt: {
|
|
5819
|
+
entry: 'sendUpdate',
|
|
5820
|
+
on: {
|
|
5821
|
+
SKIP: { target: 'resolved' },
|
|
5822
|
+
SUBMIT: { target: 'resolved' },
|
|
5823
|
+
},
|
|
5824
|
+
},
|
|
5327
5825
|
resolved: {
|
|
5328
5826
|
type: 'final',
|
|
5329
5827
|
data: (context) => ({
|
|
@@ -5361,9 +5859,10 @@ function signUpActor({ services }) {
|
|
|
5361
5859
|
return auth.signInWithRedirect(data);
|
|
5362
5860
|
},
|
|
5363
5861
|
handleSignUp(context) {
|
|
5364
|
-
const { formValues, loginMechanisms, username } = context;
|
|
5862
|
+
const { formValues, loginMechanisms, username, selectedAuthMethod, preferredChallenge, } = context;
|
|
5365
5863
|
const loginMechanism = loginMechanisms[0];
|
|
5366
|
-
const
|
|
5864
|
+
const authMethod = selectedAuthMethod ?? preferredChallenge;
|
|
5865
|
+
const input = getSignUpInput(username, formValues, loginMechanism, authMethod);
|
|
5367
5866
|
return services.handleSignUp(input);
|
|
5368
5867
|
},
|
|
5369
5868
|
async validateSignUp(context) {
|
|
@@ -5374,6 +5873,8 @@ function signUpActor({ services }) {
|
|
|
5374
5873
|
// Validation for default form fields
|
|
5375
5874
|
services.validateConfirmPassword,
|
|
5376
5875
|
services.validatePreferredUsername,
|
|
5876
|
+
// Validation for required fields based on auth method
|
|
5877
|
+
services.validateRequiredFieldsForAuthMethod,
|
|
5377
5878
|
// Validation for any custom Sign Up fields
|
|
5378
5879
|
services.validateCustomSignUp,
|
|
5379
5880
|
]);
|
|
@@ -5505,20 +6006,29 @@ function verifyUserAttributesActor() {
|
|
|
5505
6006
|
});
|
|
5506
6007
|
}
|
|
5507
6008
|
|
|
5508
|
-
const getActorContext = (context, defaultStep) =>
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
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
|
+
};
|
|
5522
6032
|
const { choose, stop } = xstate.actions;
|
|
5523
6033
|
const stopActor = (machineId) => stop(machineId);
|
|
5524
6034
|
// setup step waits for ui to emit INIT action to proceed to configure
|
|
@@ -5616,6 +6126,8 @@ function createAuthenticatorMachine(options) {
|
|
|
5616
6126
|
},
|
|
5617
6127
|
on: {
|
|
5618
6128
|
FORGOT_PASSWORD: 'forgotPasswordActor',
|
|
6129
|
+
SELECT_METHOD: { actions: 'forwardToActor' },
|
|
6130
|
+
SHOW_AUTH_METHODS: { actions: 'forwardToActor' },
|
|
5619
6131
|
SIGN_IN: 'signInActor',
|
|
5620
6132
|
SIGN_UP: 'signUpActor',
|
|
5621
6133
|
'done.invoke.signInActor': [
|
|
@@ -5782,10 +6294,11 @@ function createAuthenticatorMachine(options) {
|
|
|
5782
6294
|
}),
|
|
5783
6295
|
}),
|
|
5784
6296
|
applyAmplifyConfig: xstate.assign({
|
|
6297
|
+
passwordlessCapabilities: (_, { data: cliConfig }) => cliConfig.passwordlessCapabilities,
|
|
5785
6298
|
config(context, { data: cliConfig }) {
|
|
5786
6299
|
// Prefer explicitly configured settings over default CLI values\
|
|
5787
6300
|
const { loginMechanisms = cliConfig.loginMechanisms ?? [], signUpAttributes = cliConfig.signUpAttributes ?? [], socialProviders = cliConfig.socialProviders ?? [], initialState, formFields: _formFields, passwordSettings = cliConfig.passwordFormat ??
|
|
5788
|
-
{}, } = context.config;
|
|
6301
|
+
{}, passwordless, } = context.config;
|
|
5789
6302
|
// By default, Cognito assumes `username`, so there isn't a different username attribute like `email`.
|
|
5790
6303
|
// We explicitly add it as a login mechanism to be consistent with Admin UI's language.
|
|
5791
6304
|
if (loginMechanisms.length === 0) {
|
|
@@ -5797,6 +6310,7 @@ function createAuthenticatorMachine(options) {
|
|
|
5797
6310
|
initialState,
|
|
5798
6311
|
loginMechanisms,
|
|
5799
6312
|
passwordSettings,
|
|
6313
|
+
passwordless,
|
|
5800
6314
|
signUpAttributes,
|
|
5801
6315
|
socialProviders,
|
|
5802
6316
|
};
|