Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-init-singleton-auth-reconfigure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'aws-amplify': patch
---

fix(aws-amplify): refresh default Cognito auth config on DefaultAmplify reconfigure.
103 changes: 103 additions & 0 deletions packages/aws-amplify/__tests__/initSingleton.integration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

/**
* Integration-style tests using the real @aws-amplify/core Amplify singleton
* (initSingleton.test.ts mocks core).
*/
import { Amplify as CoreAmplify, ResourcesConfig } from '@aws-amplify/core';

import { cognitoUserPoolsTokenProvider } from '../src/auth/cognito';
import { Amplify as DefaultAmplify } from '../src';

const poolAConfig: ResourcesConfig = {
Auth: {
Cognito: {
userPoolClientId: 'client-a',
userPoolId: 'pool-a',
},
},
};

const poolBConfig: ResourcesConfig = {
Auth: {
Cognito: {
userPoolClientId: 'client-b',
userPoolId: 'pool-b',
},
},
};

describe('DefaultAmplify.configure integration', () => {
let setAuthConfigSpy: jest.SpyInstance;
let setKeyValueStorageSpy: jest.SpyInstance;

beforeEach(() => {
CoreAmplify.libraryOptions = {};
CoreAmplify.resourcesConfig = {};
setAuthConfigSpy = jest.spyOn(
cognitoUserPoolsTokenProvider,
'setAuthConfig',
);
setKeyValueStorageSpy = jest.spyOn(
cognitoUserPoolsTokenProvider,
'setKeyValueStorage',
);
});

afterEach(() => {
setAuthConfigSpy.mockRestore();
setKeyValueStorageSpy.mockRestore();
CoreAmplify.libraryOptions = {};
CoreAmplify.resourcesConfig = {};
});

it('refreshes Cognito auth config on reconfigure with partial libraryOptions', () => {
DefaultAmplify.configure(poolAConfig);

expect(setAuthConfigSpy).toHaveBeenCalledWith(poolAConfig.Auth);

setAuthConfigSpy.mockClear();
setKeyValueStorageSpy.mockClear();

DefaultAmplify.configure(poolBConfig, { ssr: false });

expect(setAuthConfigSpy).toHaveBeenCalledWith(poolBConfig.Auth);
expect(setKeyValueStorageSpy).toHaveBeenCalled();
expect(CoreAmplify.getConfig().Auth?.Cognito?.userPoolClientId).toBe(
'client-b',
);
});

it('passes through when libraryOptions.Auth is provided', () => {
DefaultAmplify.configure(poolAConfig);

setAuthConfigSpy.mockClear();

DefaultAmplify.configure(poolBConfig, {
Auth: {
tokenProvider: cognitoUserPoolsTokenProvider,
credentialsProvider:
CoreAmplify.libraryOptions.Auth!.credentialsProvider!,
},
});

expect(setAuthConfigSpy).not.toHaveBeenCalled();
expect(CoreAmplify.getConfig().Auth?.Cognito?.userPoolClientId).toBe(
'client-b',
);
});

it('refreshes Cognito auth config when only resource config is passed', () => {
DefaultAmplify.configure(poolAConfig);

setAuthConfigSpy.mockClear();
setKeyValueStorageSpy.mockClear();

DefaultAmplify.configure(poolBConfig);

expect(setAuthConfigSpy).toHaveBeenCalledWith(poolBConfig.Auth);
expect(setKeyValueStorageSpy).toHaveBeenCalled();
expect(CoreAmplify.getConfig().Auth?.Cognito?.userPoolId).toBe('pool-b');
});
});
79 changes: 66 additions & 13 deletions packages/aws-amplify/__tests__/initSingleton.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,16 +246,20 @@ describe('initSingleton (DefaultAmplify)', () => {
});

describe('when ResourcesConfig.Auth is defined', () => {
it('should just configure with the provided config and options when libraryOptions.Auth is defined', () => {
it('should pass through when libraryOptions.Auth is defined', () => {
const customTokenProvider = { getTokens: jest.fn() };
const libraryOptions = {
Auth: { tokenProvider: { getTokens: jest.fn() } },
Auth: { tokenProvider: customTokenProvider },
};
Amplify.configure(mockResourceConfig, libraryOptions);

expect(mockAmplifySingletonConfigure).toHaveBeenCalledWith(
mockResourceConfig,
libraryOptions,
);
expect(
mockCognitoUserPoolsTokenProviderSetAuthConfig,
).not.toHaveBeenCalled();
});

describe('when the singleton libraryOptions have not yet been configured with Auth', () => {
Expand Down Expand Up @@ -322,71 +326,120 @@ describe('initSingleton (DefaultAmplify)', () => {
};
});

it('should preserve current auth providers (default or otherwise) and configure provider with a new CookieStorage instance', () => {
it('should refresh default Cognito auth config and configure provider with a new CookieStorage instance on reconfigure', () => {
const libraryOptions = { ssr: true };
Amplify.configure(mockResourceConfig, libraryOptions);

expect(
mockCognitoUserPoolsTokenProviderSetAuthConfig,
).not.toHaveBeenCalled();
).toHaveBeenCalledWith(mockResourceConfig.Auth);
expect(MockCookieStorage).toHaveBeenCalledWith({ sameSite: 'lax' });
expect(
mockCognitoUserPoolsTokenProviderSetKeyValueStorage,
).toHaveBeenCalledWith(mockCookieStorageInstance);
expect(mockAmplifySingletonConfigure).toHaveBeenCalledWith(
mockResourceConfig,
{
Auth: AmplifySingleton.libraryOptions.Auth,
...libraryOptions,
Auth: {
tokenProvider: cognitoUserPoolsTokenProvider,
credentialsProvider:
mockCognitoAWSCredentialsAndIdentityIdProviderInstance,
},
},
);
});

it('should preserve current auth providers (default or otherwise) and configure provider with defaultStorage', () => {
it('should refresh default Cognito auth config and configure provider with defaultStorage on reconfigure', () => {
const libraryOptions = { ssr: false };
Amplify.configure(mockResourceConfig, libraryOptions);

expect(
mockCognitoUserPoolsTokenProviderSetAuthConfig,
).not.toHaveBeenCalled();
).toHaveBeenCalledWith(mockResourceConfig.Auth);
expect(
mockCognitoUserPoolsTokenProviderSetKeyValueStorage,
).toHaveBeenCalledWith(defaultStorage);
expect(mockAmplifySingletonConfigure).toHaveBeenCalledWith(
mockResourceConfig,
{
Auth: AmplifySingleton.libraryOptions.Auth,
...libraryOptions,
Auth: {
tokenProvider: cognitoUserPoolsTokenProvider,
credentialsProvider: cognitoCredentialsProvider,
},
},
);
});

it('should preserve current auth providers (default or otherwise)', () => {
it('should refresh default Cognito auth config when reconfiguring with non-Auth libraryOptions', () => {
const libraryOptions = {
Storage: { S3: { isObjectLockEnabled: true } },
};
Amplify.configure(mockResourceConfig, libraryOptions);

expect(
mockCognitoUserPoolsTokenProviderSetAuthConfig,
).not.toHaveBeenCalled();
).toHaveBeenCalledWith(mockResourceConfig.Auth);
expect(
mockCognitoUserPoolsTokenProviderSetKeyValueStorage,
).not.toHaveBeenCalled();
).toHaveBeenCalledWith(defaultStorage);
expect(mockAmplifySingletonConfigure).toHaveBeenCalledWith(
mockResourceConfig,
{
Auth: AmplifySingleton.libraryOptions.Auth,
...libraryOptions,
Auth: {
tokenProvider: cognitoUserPoolsTokenProvider,
credentialsProvider: cognitoCredentialsProvider,
},
},
);
});

it('should just configure without touching libraryOptions', () => {
it('should refresh default Cognito auth config when reconfiguring with resource config only', () => {
Amplify.configure(mockResourceConfig);

expect(
mockCognitoUserPoolsTokenProviderSetAuthConfig,
).toHaveBeenCalledWith(mockResourceConfig.Auth);
expect(
mockCognitoUserPoolsTokenProviderSetKeyValueStorage,
).toHaveBeenCalledWith(defaultStorage);
expect(mockAmplifySingletonConfigure).toHaveBeenCalledWith(
mockResourceConfig,
{
Auth: {
tokenProvider: cognitoUserPoolsTokenProvider,
credentialsProvider: cognitoCredentialsProvider,
},
},
);
});

it('should pass through when libraryOptions.Auth is provided on reconfigure', () => {
const updatedResourceConfig: ResourcesConfig = {
Auth: {
Cognito: {
userPoolClientId: 'newClientId',
userPoolId: 'newPoolId',
},
},
};
const libraryOptions = {
Auth: {
tokenProvider: cognitoUserPoolsTokenProvider,
credentialsProvider: cognitoCredentialsProvider,
},
};

Amplify.configure(updatedResourceConfig, libraryOptions);

expect(
mockCognitoUserPoolsTokenProviderSetAuthConfig,
).not.toHaveBeenCalled();
expect(mockAmplifySingletonConfigure).toHaveBeenCalledWith(
updatedResourceConfig,
libraryOptions,
);
});
});
Expand Down
67 changes: 13 additions & 54 deletions packages/aws-amplify/src/initSingleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,66 +48,25 @@ export const DefaultAmplify = {
)
: cognitoCredentialsProvider;

// If no Auth config is provided, no special handling will be required, configure as is.
// Otherwise, we can assume an Auth config is provided from here on.
if (!resolvedResourceConfig.Auth) {
if (!resolvedResourceConfig.Auth || libraryOptions?.Auth) {
Amplify.configure(resolvedResourceConfig, libraryOptions);

return;
}

// If Auth options are provided, always just configure as is.
// Otherwise, we can assume no Auth libraryOptions were provided from here on.
if (libraryOptions?.Auth) {
Amplify.configure(resolvedResourceConfig, libraryOptions);

return;
}

// If no Auth libraryOptions were previously configured, then always add default providers.
if (!Amplify.libraryOptions.Auth) {
cognitoUserPoolsTokenProvider.setAuthConfig(resolvedResourceConfig.Auth);
cognitoUserPoolsTokenProvider.setKeyValueStorage(
// TODO: allow configure with a public interface
resolvedKeyValueStorage,
);

Amplify.configure(resolvedResourceConfig, {
...libraryOptions,
Auth: {
tokenProvider: cognitoUserPoolsTokenProvider,
credentialsProvider: resolvedCredentialsProvider,
},
});

return;
}

// At this point, Auth libraryOptions would have been previously configured and no overriding
// Auth options were given, so we should preserve the currently configured Auth libraryOptions.
if (libraryOptions) {
const authLibraryOptions = Amplify.libraryOptions.Auth;
// If ssr is provided through libraryOptions, we should respect the intentional reconfiguration.
if (libraryOptions.ssr !== undefined) {
cognitoUserPoolsTokenProvider.setKeyValueStorage(
// TODO: allow configure with a public interface
resolvedKeyValueStorage,
);

authLibraryOptions.credentialsProvider = resolvedCredentialsProvider;
}

Amplify.configure(resolvedResourceConfig, {
Auth: authLibraryOptions,
...libraryOptions,
});

return;
}
cognitoUserPoolsTokenProvider.setAuthConfig(resolvedResourceConfig.Auth);
cognitoUserPoolsTokenProvider.setKeyValueStorage(
// TODO: allow configure with a public interface
resolvedKeyValueStorage,
);

// Finally, if there were no libraryOptions given at all, we should simply not touch the currently
// configured libraryOptions.
Amplify.configure(resolvedResourceConfig);
Amplify.configure(resolvedResourceConfig, {
...libraryOptions,
Auth: {
tokenProvider: cognitoUserPoolsTokenProvider,
credentialsProvider: resolvedCredentialsProvider,
},
});
},
/**
* Returns the {@link ResourcesConfig} object passed in as the `resourceConfig` parameter when calling
Expand Down
Loading