diff --git a/packages/aws-amplify/package.json b/packages/aws-amplify/package.json index abb62b54ae5..93f259c5fe6 100644 --- a/packages/aws-amplify/package.json +++ b/packages/aws-amplify/package.json @@ -293,31 +293,31 @@ "name": "[Analytics] record (Pinpoint)", "path": "./dist/esm/analytics/index.mjs", "import": "{ record }", - "limit": "17.09 kB" + "limit": "17.15 kB" }, { "name": "[Analytics] record (Kinesis)", "path": "./dist/esm/analytics/kinesis/index.mjs", "import": "{ record }", - "limit": "48.56 kB" + "limit": "48.59 kB" }, { "name": "[Analytics] record (Kinesis Firehose)", "path": "./dist/esm/analytics/kinesis-firehose/index.mjs", "import": "{ record }", - "limit": "45.68 kB" + "limit": "45.72 kB" }, { "name": "[Analytics] record (Personalize)", "path": "./dist/esm/analytics/personalize/index.mjs", "import": "{ record }", - "limit": "49.50 kB" + "limit": "49.54 kB" }, { "name": "[Analytics] identifyUser (Pinpoint)", "path": "./dist/esm/analytics/index.mjs", "import": "{ identifyUser }", - "limit": "15.59 kB" + "limit": "15.65 kB" }, { "name": "[Analytics] enable", @@ -335,7 +335,7 @@ "name": "[API] generateClient (AppSync)", "path": "./dist/esm/api/index.mjs", "import": "{ generateClient }", - "limit": "40.09 kB" + "limit": "40.11 kB" }, { "name": "[API] REST API handlers", @@ -353,13 +353,13 @@ "name": "[Auth] resetPassword (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ resetPassword }", - "limit": "12.44 kB" + "limit": "12.48 kB" }, { "name": "[Auth] confirmResetPassword (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ confirmResetPassword }", - "limit": "12.39 kB" + "limit": "12.43 kB" }, { "name": "[Auth] signIn (Cognito)", @@ -371,7 +371,7 @@ "name": "[Auth] resendSignUpCode (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ resendSignUpCode }", - "limit": "12.40 kB" + "limit": "12.44 kB" }, { "name": "[Auth] confirmSignUp (Cognito)", @@ -383,31 +383,31 @@ "name": "[Auth] confirmSignIn (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ confirmSignIn }", - "limit": "28.27 kB" + "limit": "28.33 kB" }, { "name": "[Auth] updateMFAPreference (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ updateMFAPreference }", - "limit": "11.74 kB" + "limit": "11.78 kB" }, { "name": "[Auth] fetchMFAPreference (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ fetchMFAPreference }", - "limit": "11.78 kB" + "limit": "11.82 kB" }, { "name": "[Auth] verifyTOTPSetup (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ verifyTOTPSetup }", - "limit": "12.6 kB" + "limit": "12.65 kB" }, { "name": "[Auth] updatePassword (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ updatePassword }", - "limit": "12.63 kB" + "limit": "12.67 kB" }, { "name": "[Auth] setUpTOTP (Cognito)", @@ -419,19 +419,19 @@ "name": "[Auth] updateUserAttributes (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ updateUserAttributes }", - "limit": "11.87 kB" + "limit": "11.90 kB" }, { "name": "[Auth] getCurrentUser (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ getCurrentUser }", - "limit": "7.75 kB" + "limit": "7.80 kB" }, { "name": "[Auth] confirmUserAttribute (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ confirmUserAttribute }", - "limit": "12.61 kB" + "limit": "12.65 kB" }, { "name": "[Auth] signInWithRedirect (Cognito)", @@ -443,55 +443,55 @@ "name": "[Auth] fetchUserAttributes (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ fetchUserAttributes }", - "limit": "11.69 kB" + "limit": "11.73 kB" }, { "name": "[Auth] Basic Auth Flow (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ signIn, signOut, fetchAuthSession, confirmSignIn }", - "limit": "30.06 kB" + "limit": "30.12 kB" }, { "name": "[Auth] OAuth Auth Flow (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ signInWithRedirect, signOut, fetchAuthSession }", - "limit": "21.47 kB" + "limit": "21.53 kB" }, { "name": "[Storage] copy (S3)", "path": "./dist/esm/storage/index.mjs", "import": "{ copy }", - "limit": "14.54 kB" + "limit": "14.57 kB" }, { "name": "[Storage] downloadData (S3)", "path": "./dist/esm/storage/index.mjs", "import": "{ downloadData }", - "limit": "15.17 kB" + "limit": "15.20 kB" }, { "name": "[Storage] getProperties (S3)", "path": "./dist/esm/storage/index.mjs", "import": "{ getProperties }", - "limit": "14.43 kB" + "limit": "14.47 kB" }, { "name": "[Storage] getUrl (S3)", "path": "./dist/esm/storage/index.mjs", "import": "{ getUrl }", - "limit": "15.51 kB" + "limit": "15.55 kB" }, { "name": "[Storage] list (S3)", "path": "./dist/esm/storage/index.mjs", "import": "{ list }", - "limit": "15.04 kB" + "limit": "15.08 kB" }, { "name": "[Storage] remove (S3)", "path": "./dist/esm/storage/index.mjs", "import": "{ remove }", - "limit": "14.29 kB" + "limit": "14.33 kB" }, { "name": "[Storage] uploadData (S3)", diff --git a/packages/core/__tests__/singleton/Singleton.test.ts b/packages/core/__tests__/singleton/Singleton.test.ts index 03c0185359d..e9d58ed2c07 100644 --- a/packages/core/__tests__/singleton/Singleton.test.ts +++ b/packages/core/__tests__/singleton/Singleton.test.ts @@ -4,8 +4,12 @@ import { Amplify } from '../../src/singleton'; import { AMPLIFY_SYMBOL, Hub } from '../../src/Hub'; import { AuthClass as Auth } from '../../src/singleton/Auth'; import { decodeJWT } from '../../src/singleton/Auth/utils'; -import { CredentialsAndIdentityId } from '../../src/singleton/Auth/types'; +import { + CognitoUserPoolConfig, + CredentialsAndIdentityId, +} from '../../src/singleton/Auth/types'; import { ResourcesConfig, fetchAuthSession } from '../../src'; +import { ADD_OAUTH_LISTENER } from '../../src/libraryUtils'; Object.assign(global, { TextDecoder, TextEncoder }); @@ -255,6 +259,64 @@ describe('Amplify.configure() and Amplify.getConfig()', () => { expect(config3).not.toBe(config); expect(config3).not.toBe(config2); }); + + describe('with oAuthListener', () => { + const mockCognitoConfig: CognitoUserPoolConfig = { + userPoolId: 'xxxxxxxx', + userPoolClientId: 'xxxxxxx', + }; + const mockOAuthConfig: CognitoUserPoolConfig = { + ...mockCognitoConfig, + loginWith: { + oauth: { + domain: 'domain', + redirectSignIn: ['localhost:3000'], + redirectSignOut: ['localhost:3000'], + scopes: ['profile'], + responseType: 'code', + }, + }, + }; + const mockInvalidOAuthConfig: CognitoUserPoolConfig = { + ...mockCognitoConfig, + loginWith: { + oauth: { + domain: 'invalidDomain', + redirectSignIn: ['localhost:3000'], + redirectSignOut: ['localhost:3000'], + scopes: ['profile'], + responseType: 'code', + }, + }, + }; + const mockOAuthlistener = jest.fn(); + + beforeEach(() => { + Amplify[ADD_OAUTH_LISTENER](mockOAuthlistener); + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + it('should not call oAuthListener when OAuth config is not defined', async () => { + Amplify.configure({ Auth: { Cognito: mockCognitoConfig } }); + expect(mockOAuthlistener).not.toHaveBeenCalled(); + }); + + it('should call oAuthListener when OAuth config and oAuthListener are defined', async () => { + Amplify.configure({ Auth: { Cognito: mockOAuthConfig } }); + jest.runAllTimers(); + expect(mockOAuthlistener).toHaveBeenCalledWith(mockOAuthConfig); + }); + + it('should call oAuthListener with the latest config', async () => { + Amplify.configure({ Auth: { Cognito: mockInvalidOAuthConfig } }); + Amplify.configure({ Auth: { Cognito: mockOAuthConfig } }); + jest.runAllTimers(); + expect(mockOAuthlistener).toHaveBeenCalledWith(mockOAuthConfig); + }); + }); }); describe('Session tests', () => { diff --git a/packages/core/src/singleton/Amplify.ts b/packages/core/src/singleton/Amplify.ts index 76d4e5be9b4..0690f6f219b 100644 --- a/packages/core/src/singleton/Amplify.ts +++ b/packages/core/src/singleton/Amplify.ts @@ -13,14 +13,14 @@ import { } from './types'; import { AuthClass } from './Auth'; import { ADD_OAUTH_LISTENER } from './constants'; +import { OAuthListener } from './Auth/types'; export class AmplifyClass { - private oAuthListener: - | ((authConfig: AuthConfig['Cognito']) => void) - | undefined = undefined; + private oAuthListener: OAuthListener | undefined = undefined; resourcesConfig: ResourcesConfig; libraryOptions: LibraryOptions; + private listenerTimeout?: ReturnType; /** * Cross-category Auth utilities. @@ -53,7 +53,6 @@ export class AmplifyClass { libraryOptions?: LibraryOptions, ): void { const resolvedResourceConfig = parseAmplifyConfig(resourcesConfig); - this.resourcesConfig = resolvedResourceConfig; if (libraryOptions) { @@ -75,7 +74,10 @@ export class AmplifyClass { AMPLIFY_SYMBOL, ); - this.notifyOAuthListener(); + const config = this.resourcesConfig.Auth?.Cognito; + if (config?.loginWith?.oauth && this.oAuthListener) { + this.notifyOAuthListener(this, config, this.oAuthListener); + } } /** @@ -98,17 +100,27 @@ export class AmplifyClass { } } - private notifyOAuthListener() { - if ( - !this.resourcesConfig.Auth?.Cognito.loginWith?.oauth || - !this.oAuthListener - ) { - return; + private notifyOAuthListener( + amplify: AmplifyClass, + config: AuthConfig['Cognito'], + oAuthListener: OAuthListener, + ) { + if (amplify.listenerTimeout) { + amplify.clearListenerTimeout(); } + // The setTimeout will only be called as long as an oAuthLister and oauth config + // are defined. The code executed by the time out will be only fired once. + amplify.listenerTimeout = setTimeout(() => { + oAuthListener(config); + // the listener should only be notified once with a valid oauth config + amplify.oAuthListener = undefined; + amplify.clearListenerTimeout(); + }); + } - this.oAuthListener(this.resourcesConfig.Auth?.Cognito); - // the listener should only be notified once with a valid oauth config - this.oAuthListener = undefined; + private clearListenerTimeout() { + clearTimeout(this.listenerTimeout); + this.listenerTimeout = undefined; } } diff --git a/packages/core/src/singleton/Auth/types.ts b/packages/core/src/singleton/Auth/types.ts index 239810e8771..a9d1c99af54 100644 --- a/packages/core/src/singleton/Auth/types.ts +++ b/packages/core/src/singleton/Auth/types.ts @@ -259,3 +259,5 @@ type AuthFlowType = | 'CUSTOM_WITH_SRP' | 'CUSTOM_WITHOUT_SRP' | 'USER_PASSWORD_AUTH'; + +export type OAuthListener = (authConfig: AuthConfig['Cognito']) => void; diff --git a/packages/interactions/package.json b/packages/interactions/package.json index 0677b8ef889..c9d38d75d72 100644 --- a/packages/interactions/package.json +++ b/packages/interactions/package.json @@ -89,19 +89,19 @@ "name": "Interactions (default to Lex v2)", "path": "./dist/esm/index.mjs", "import": "{ Interactions }", - "limit": "52.52 kB" + "limit": "52.57 kB" }, { "name": "Interactions (Lex v2)", "path": "./dist/esm/lex-v2/index.mjs", "import": "{ Interactions }", - "limit": "52.52 kB" + "limit": "52.57 kB" }, { "name": "Interactions (Lex v1)", "path": "./dist/esm/lex-v1/index.mjs", "import": "{ Interactions }", - "limit": "47.33 kB" + "limit": "47.38 kB" } ] }