AmplifySignUp doesn't detect values of text fields after initial submission failure
See original GitHub issueBefore opening, please confirm:
- I have searched for duplicate or closed issues and discussions.
- I have read the guide for submitting bug reports.
- I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
JavaScript Framework
React
Amplify APIs
Not applicable
Amplify Categories
Not applicable
Environment information
# Put output below this line
System:
OS: macOS 11.5.1
CPU: (8) x64 Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
Memory: 944.93 MB / 16.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 14.15.5 - /usr/local/bin/node
Yarn: 1.22.10 - /usr/local/bin/yarn
npm: 6.14.14 - /usr/local/bin/npm
npmPackages:
@aws-amplify/ui-react: ^1.2.8 => 1.2.8
@popperjs/core: ^2.9.2 => 2.9.3
@testing-library/jest-dom: ^5.11.4 => 5.14.1
@testing-library/react: ^11.1.0 => 11.2.7
@testing-library/user-event: ^12.1.10 => 12.8.3
autoprefixer: ^9.8.6 => 9.8.6
aws-amplify: ^4.2.2 => 4.2.2
bootstrap: ^5.0.2 => 5.1.0
bootstrap-icons: ^1.5.0 => 1.5.0
husky: ^7.0.0 => 7.0.1
lerna: ^4.0.0 => 4.0.0
node-sass: ^6.0.1 => 6.0.1
prettier: ^2.3.2 => 2.3.2
pretty-quick: ^3.1.1 => 3.1.1
react: ^17.0.2 => 17.0.2
react-dom: ^17.0.2 => 17.0.2
react-scripts: 4.0.3 => 4.0.3
redux-logger: ^3.0.6 => 3.0.6
workbox-background-sync: ^5.1.3 => 5.1.4
workbox-broadcast-update: ^5.1.3 => 5.1.4
workbox-cacheable-response: ^5.1.3 => 5.1.4
workbox-core: ^5.1.3 => 5.1.4
workbox-expiration: ^5.1.3 => 5.1.4
workbox-google-analytics: ^5.1.3 => 5.1.4
workbox-navigation-preload: ^5.1.3 => 5.1.4
workbox-precaching: ^5.1.3 => 5.1.4
workbox-range-requests: ^5.1.3 => 5.1.4
workbox-routing: ^5.1.3 => 5.1.4
workbox-strategies: ^5.1.3 => 5.1.4
workbox-streams: ^5.1.3 => 5.1.4
Describe the bug
When using a custom AmplifyAuthenticator
and trying to sign up, if registration fails because only one of the fields was wrong, the user updates the field in the form to fix it. Because the user is only updating one field it always throws Password cannot be empty
or Email cannot be empty
. The only way to overcome that is to modify both email and password fields before submitting. If the user only modifies one field the form always fails.
Expected behavior
When a user fixes the form and clicks submit again the form should call the Cognito API to create the user.
Reproduction steps
- Go to Sign Up page
- Fill out sign up form with incorrect data (email already been used or incorrect password policy)
- Submit and wait for failure
- Fix only one of the text inputs (email or password)
- Submit
- If email was updated it says password is empty (it is not). If password is updated it says email is empty (it is not)
- Update both fields and submit
- Submission now works
Code Snippet
Wrapping App.jsx
with custom withAuthenticator
Code for withAuthenticator.jsx
import { useEffect, useState } from 'react'
import { Auth, appendToCognitoUserAgent } from '@aws-amplify/auth'
import { Hub, Logger } from '@aws-amplify/core'
import {
AmplifyContainer,
AmplifyAuthenticator,
AmplifyAuthContainer,
AmplifySignIn,
AmplifySignUp,
AmplifyConfirmSignIn,
AmplifyConfirmSignUp,
AmplifyForgotPassword,
AmplifyRequireNewPassword,
AmplifyTotpSetup,
AmplifyVerifyContact
} from '@aws-amplify/ui-react'
import {
UI_AUTH_CHANNEL,
TOAST_AUTH_ERROR_EVENT,
AuthState,
onAuthUIStateChange
} from '@aws-amplify/ui-components'
import Toast from '../Toast'
const logger = new Logger('withAuthenticator')
function applyStylesToShashowComponent(querySelector) {
const style = document.createElement('style')
style.innerHTML = '.button { border-radius: 0.25rem!important; }'
const host = document.querySelector(querySelector)
host.shadowRoot.appendChild(style)
}
function withAuthenticator(Component, authenticatorProps) {
const AppWithAuthenticator = props => {
const [errorMessage, setErrorMessage] = useState(null)
const [signedIn, setSignedIn] = useState(false)
useEffect(() => {
Hub.listen(UI_AUTH_CHANNEL, handleHubEvents)
return () => {
Hub.remove(UI_AUTH_CHANNEL, handleHubEvents)
}
})
useEffect(() => {
appendToCognitoUserAgent('withAuthenticator')
const shadowComponents = [
'amplify-sign-in',
'amplify-sign-up',
'amplify-confirm-sign-in',
'amplify-confirm-sign-up',
'amplify-forgot-password',
'amplify-require-new-password',
'amplify-totp-setup',
'amplify-verify-contact'
]
shadowComponents.forEach(applyStylesToShashowComponent)
return checkUser()
}, [])
function checkUser() {
setUser()
return onAuthUIStateChange(authState => {
if (authState === AuthState.SignedIn) {
setSignedIn(true)
} else if (authState === AuthState.SignedOut) {
setSignedIn(false)
}
})
}
function handleHubEvents({ payload }) {
setErrorMessage(null)
logger.debug(payload)
if (payload.event === TOAST_AUTH_ERROR_EVENT && payload.message) {
setErrorMessage(payload.message)
}
}
function onClickCloseError(e) {
e.preventDefault()
setErrorMessage(null)
}
async function setUser() {
try {
const user = await Auth.currentAuthenticatedUser()
if (user) setSignedIn(true)
} catch (err) {
logger.debug(err)
}
}
if (!signedIn) {
return (
<AmplifyContainer>
<AmplifyAuthContainer>
{errorMessage && (
<Toast message={errorMessage} onClickClose={onClickCloseError} />
)}
<AmplifyAuthenticator
{...authenticatorProps}
{...props}
usernameAlias={'email'}
hideToast={true}
>
<AmplifySignIn slot={'sign-in'} usernameAlias={'email'} />
<AmplifySignUp
slot={'sign-up'}
usernameAlias={'email'}
formFields={[
{
type: 'email',
placeholder: 'Enter your email address'
},
{
type: 'password',
placeholder: 'Enter your new password',
hint: 'Must be 8 characters long, at least 1 capital letter, 1 lower case letter, 1 number and 1 symbol.'
}
]}
/>
<AmplifyConfirmSignIn slot={'confirm-sign-in'} />
<AmplifyConfirmSignUp
slot={'confirm-sign-up'}
usernameAlias={'email'}
/>
<AmplifyForgotPassword
slot={'forgot-password'}
usernameAlias={'email'}
/>
<AmplifyRequireNewPassword slot={'require-new-password'} />
<AmplifyTotpSetup slot={'totp-setup'} />
<AmplifyVerifyContact slot={'verify-contact'} />
</AmplifyAuthenticator>
</AmplifyAuthContainer>
</AmplifyContainer>
)
}
return <Component {...props} />
}
return AppWithAuthenticator
}
export default withAuthenticator
Log output
// Put your logs below this line
aws-exports.js
No response
Manual configuration
Amplify.configure({
Auth: {
identityPoolId: 'us-east-1:#######',
region: 'us-east-1',
userPoolId: 'us-east-1_#######',
userPoolWebClientId: '#######',
mandatorySignIn: false,
authenticationFlowType: 'USER_SRP_AUTH'
}
})
Additional configuration
No response
Mobile Device
No response
Mobile Operating System
No response
Mobile Browser
No response
Mobile Browser Version
No response
Additional information and screenshots
https://user-images.githubusercontent.com/3858265/129182560-00111fe5-d5bd-4ad0-958a-eb4bcc535c79.mov
Issue Analytics
- State:
- Created 2 years ago
- Comments:8 (3 by maintainers)
Confirmed this is fixed in
@next
:https://user-images.githubusercontent.com/15182/140546236-f17facf0-4b5b-446a-91f6-4e84f1de2e11.mp4
This also works as expected for custom fields appended to the form:
Unfortunately, the architecture for the previous implementation around
formFields
basically wipes out values between renders, which is what caused this bug.The new implementation respects existing values and correctly updates them.
Thanks @ericclemmons ! Yes, your suggestion worked. Sorry, I’m getting used to the new syntax and it seems like my mishmash combo seemed to work in some nightly(?)
@next
build.The following worked for me (using a fresh
@next
install, if it matters):