diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yaml b/.github/ISSUE_TEMPLATE/1.bug_report.yaml index cd78d0ca85a..8f61ff5bf9d 100644 --- a/.github/ISSUE_TEMPLATE/1.bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/1.bug_report.yaml @@ -75,6 +75,7 @@ body: - React Native - Vue - Web Components + - Next.js - Not applicable validations: required: true diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 1665e61aed9..306620b5420 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -225,7 +225,7 @@ GEM rb-fsevent (0.10.4) rb-inotify (0.10.1) ffi (~> 1.0) - rexml (3.2.4) + rexml (3.2.5) rouge (3.26.0) ruby-enum (0.9.0) i18n diff --git a/packages/amazon-cognito-identity-js/README.md b/packages/amazon-cognito-identity-js/README.md index 44fcdaf1f90..ce20854f076 100644 --- a/packages/amazon-cognito-identity-js/README.md +++ b/packages/amazon-cognito-identity-js/README.md @@ -724,18 +724,30 @@ cognitoUser.forgetDevice({ ``` -**Use case 24.** Retrieve the MFA Options for the user in case MFA is optional. +**Use case 24.** Retrieve the MFA settings for the user. ```javascript -cognitoUser.getMFAOptions(function(err, mfaOptions) { +cognitoUser.getUserData((err, data) => { if (err) { alert(err.message || JSON.stringify(err)); return; } - console.log('MFA options for user ' + mfaOptions); + const { PreferredMfaSetting, UserMFASettingList } = data; + console.log( + JSON.stringify({ PreferredMfaSetting, UserMFASettingList }, null, 2) + ); }); ``` +E.g. + +```json +{ + "PreferredMfaSetting": "SMS_MFA", + "UserMFASettingList": ["SMS_MFA"] +} +``` + **Use case 25.** Authenticating a user with a passwordless custom flow. ```javascript diff --git a/packages/amazon-cognito-identity-js/src/CognitoUser.js b/packages/amazon-cognito-identity-js/src/CognitoUser.js index e7be3c9769c..cbf5e1f4ca2 100644 --- a/packages/amazon-cognito-identity-js/src/CognitoUser.js +++ b/packages/amazon-cognito-identity-js/src/CognitoUser.js @@ -1182,7 +1182,10 @@ export default class CognitoUser { } /** - * This is used by an authenticated user to get the MFAOptions + * This was previously used by an authenticated user to get MFAOptions, + * but no longer returns a meaningful response. Refer to the documentation for + * how to setup and use MFA: https://docs.amplify.aws/lib/auth/mfa/q/platform/js + * @deprecated * @param {nodeCallback} callback Called on success or error. * @returns {void} */ diff --git a/packages/amplify-ui-components/src/components/amplify-input/amplify-input.tsx b/packages/amplify-ui-components/src/components/amplify-input/amplify-input.tsx index b783eea9656..f51f42d035f 100644 --- a/packages/amplify-ui-components/src/components/amplify-input/amplify-input.tsx +++ b/packages/amplify-ui-components/src/components/amplify-input/amplify-input.tsx @@ -36,6 +36,7 @@ export class AmplifyInput { */ private setAutoCompleteValue(value: string) { const input = this.el.querySelector('input'); + if (!input) return; input.value = value; // dispatch an input event from this element to the parent form input.dispatchEvent(new Event('input')); @@ -76,10 +77,12 @@ export class AmplifyInput { * which is the existing behavior. */ const input = this.el.querySelector('input'); - input.value = ''; + if (input) input.value = ''; this.autoCompleted = false; }); + } + componentDidLoad() { // no-op if this field already has been autofilled or already has an value if (this.autoCompleted || this.value) return; diff --git a/packages/amplify-ui-components/src/components/amplify-sign-in/amplify-sign-in.tsx b/packages/amplify-ui-components/src/components/amplify-sign-in/amplify-sign-in.tsx index 9a4635c694d..24ca85ee82c 100644 --- a/packages/amplify-ui-components/src/components/amplify-sign-in/amplify-sign-in.tsx +++ b/packages/amplify-ui-components/src/components/amplify-sign-in/amplify-sign-in.tsx @@ -105,6 +105,8 @@ export class AmplifySignIn { return event => handlePhoneNumberChange(event, this.phoneNumber); case 'password': return event => (this.signInAttributes.password = event.target.value); + default: + return () => {}; } } diff --git a/packages/amplify-ui-react/__tests__/withAuthenticator-test.tsx b/packages/amplify-ui-react/__tests__/withAuthenticator-test.tsx index 9f0c9245a8f..cea1c5f4be2 100644 --- a/packages/amplify-ui-react/__tests__/withAuthenticator-test.tsx +++ b/packages/amplify-ui-react/__tests__/withAuthenticator-test.tsx @@ -12,4 +12,20 @@ describe('withAuthenticator', () => { `""` ); }); + + it('should pass through props to the wrapped component', () => { + const Dummy = ({ prop1 }) =>
{prop1}
; + const mockProp = 'mockProp'; + + const useStateSpy = jest.spyOn(React, 'useState'); + useStateSpy.mockReturnValue([true, () => {}]); + + const Wrapped = withAuthenticator(Dummy); + + expect(renderToStaticMarkup()).toMatchInlineSnapshot( + `"
${mockProp}
"` + ); + + useStateSpy.mockRestore(); + }); }); diff --git a/packages/amplify-ui-react/src/withAuthenticator.tsx b/packages/amplify-ui-react/src/withAuthenticator.tsx index 63e0326a9a3..0caccfe89da 100644 --- a/packages/amplify-ui-react/src/withAuthenticator.tsx +++ b/packages/amplify-ui-react/src/withAuthenticator.tsx @@ -10,11 +10,11 @@ import { Logger } from '@aws-amplify/core'; const logger = new Logger('withAuthenticator'); -export function withAuthenticator( - Component: ComponentType, +export function withAuthenticator( + Component: ComponentType, authenticatorProps?: ComponentPropsWithRef ) { - const AppWithAuthenticator: FunctionComponent = props => { + const AppWithAuthenticator: FunctionComponent = props => { const [signedIn, setSignedIn] = React.useState(false); React.useEffect(() => { @@ -52,7 +52,8 @@ export function withAuthenticator( ); } - return ; + + return ; }; return AppWithAuthenticator; diff --git a/packages/auth/__tests__/oauth-test.ts b/packages/auth/__tests__/oauth-test.ts index 19e7b8b8dc2..02d1ef5d915 100644 --- a/packages/auth/__tests__/oauth-test.ts +++ b/packages/auth/__tests__/oauth-test.ts @@ -145,5 +145,44 @@ describe('OAuth', () => { expect(err.message).toBe(mockError); } }); + test('Tokens are returned when the currentUrl has three slashes', async () => { + const redirectSignIn = 'myapp://'; + const currentUrl = 'myapp:///'; + + const config = { + domain: '', + clientID: '', + scope: '', + redirectUri: '', + audience: '', + responseType: 'code', + returnTo: '', + redirectSignIn, + }; + const oAuth = new OAuth({ + scopes: [], + config, + cognitoClientId: '', + }); + const mockAccessToken = 'mockAccessToken'; + const mockRefreshToken = 'mockRefreshToken'; + const mockIdToken = 'mockIdToken'; + + fetchMockReturn({ + access_token: mockAccessToken, + refresh_token: mockRefreshToken, + id_token: mockIdToken, + }); + + const handleResponse = await oAuth.handleAuthResponse( + `${currentUrl}?code=12345` + ); + expect(handleResponse).toEqual({ + state: undefined, + accessToken: mockAccessToken, + refreshToken: mockRefreshToken, + idToken: mockIdToken, + }); + }); }); }); diff --git a/packages/auth/src/Auth.ts b/packages/auth/src/Auth.ts index ac231c276ed..e7e7c55e90f 100644 --- a/packages/auth/src/Auth.ts +++ b/packages/auth/src/Auth.ts @@ -328,7 +328,10 @@ export class AuthClass { validationData = []; Object.keys(validationDataObject).map(key => { validationData.push( - new CognitoUserAttribute({ Name: key, Value: validationDataObject[key] }) + new CognitoUserAttribute({ + Name: key, + Value: validationDataObject[key], + }) ); }); } @@ -650,8 +653,9 @@ export class AuthClass { } /** - * get user current preferred mfa option - * this method doesn't work with totp, we need to deprecate it. + * This was previously used by an authenticated user to get MFAOptions, + * but no longer returns a meaningful response. Refer to the documentation for + * how to setup and use MFA: https://docs.amplify.aws/lib/auth/mfa/q/platform/js * @deprecated * @param {CognitoUser} user - the current user * @return - A promise resolves the current preferred mfa option if success diff --git a/packages/auth/src/OAuth/OAuth.ts b/packages/auth/src/OAuth/OAuth.ts index c5387dcb75d..2ac97e29da2 100644 --- a/packages/auth/src/OAuth/OAuth.ts +++ b/packages/auth/src/OAuth/OAuth.ts @@ -125,7 +125,11 @@ export default class OAuth { .map(pairings => pairings.split('=')) .reduce((accum, [k, v]) => ({ ...accum, [k]: v }), { code: undefined }); - if (!code || parse(currentUrl).pathname !== parse(this._config.redirectSignIn).pathname) { + const currentUrlPathname = parse(currentUrl).pathname || '/'; + const redirectSignInPathname = + parse(this._config.redirectSignIn).pathname || '/'; + + if (!code || currentUrlPathname !== redirectSignInPathname) { return; }