From b2311b848e28bd5b6ad029ec742c8c6d9a907fdb Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Wed, 17 Sep 2025 16:57:43 +0200 Subject: [PATCH 01/10] feat: support clientmetadata for token refresh --- .../providers/cognito/refreshToken.test.ts | 34 ++++++++++++++++++ .../setTokenRefreshClientMetadata.test.ts | 21 +++++++++++ .../cognito/tokenOrchestrator.test.ts | 35 +++++++++++++++++++ .../apis/setTokenRefreshClientMetadata.ts | 17 +++++++++ packages/auth/src/providers/cognito/index.ts | 1 + .../tokenProvider/TokenOrchestrator.ts | 11 +++++- .../providers/cognito/tokenProvider/types.ts | 5 ++- .../cognito/utils/refreshAuthTokens.ts | 4 +++ packages/core/src/singleton/Auth/types.ts | 1 + 9 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 packages/auth/__tests__/providers/cognito/setTokenRefreshClientMetadata.test.ts create mode 100644 packages/auth/src/providers/cognito/apis/setTokenRefreshClientMetadata.ts diff --git a/packages/auth/__tests__/providers/cognito/refreshToken.test.ts b/packages/auth/__tests__/providers/cognito/refreshToken.test.ts index a298e1aa377..feb41304b0e 100644 --- a/packages/auth/__tests__/providers/cognito/refreshToken.test.ts +++ b/packages/auth/__tests__/providers/cognito/refreshToken.test.ts @@ -1,3 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { refreshAuthTokens } from '../../../src/providers/cognito/utils/refreshAuthTokens'; @@ -97,6 +100,37 @@ describe('refreshToken', () => { ); }); + it('passes clientMetadata to getTokensFromRefreshToken', async () => { + const clientMetadata = { 'app-version': '1.0.0' }; + + await refreshAuthTokens({ + username: mockedUsername, + tokens: { + accessToken: { payload: {} }, + idToken: { payload: {} }, + clockDrift: 0, + refreshToken: mockedRefreshToken, + username: mockedUsername, + }, + authConfig: { + Cognito: { + userPoolId: 'us-east-1_aaaaaaa', + userPoolClientId: 'aaaaaaaaaaaa', + }, + }, + clientMetadata, + }); + + expect(mockGetTokensFromRefreshToken).toHaveBeenCalledWith( + expect.objectContaining({ region: 'us-east-1' }), + expect.objectContaining({ + ClientId: 'aaaaaaaaaaaa', + RefreshToken: mockedRefreshToken, + ClientMetadata: clientMetadata, + }), + ); + }); + it('invokes mockCreateCognitoUserPoolEndpointResolver with expected parameters', async () => { const expectedParam = 'https://my-custom-endpoint.com'; const expectedEndpointResolver = jest.fn(); diff --git a/packages/auth/__tests__/providers/cognito/setTokenRefreshClientMetadata.test.ts b/packages/auth/__tests__/providers/cognito/setTokenRefreshClientMetadata.test.ts new file mode 100644 index 00000000000..0aab0eb6072 --- /dev/null +++ b/packages/auth/__tests__/providers/cognito/setTokenRefreshClientMetadata.test.ts @@ -0,0 +1,21 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { setTokenRefreshClientMetadata } from '../../../src/providers/cognito/apis/setTokenRefreshClientMetadata'; +import { tokenOrchestrator } from '../../../src/providers/cognito/tokenProvider'; + +jest.mock('../../../src/providers/cognito/tokenProvider'); + +const mockTokenOrchestrator = jest.mocked(tokenOrchestrator); + +describe('setTokenRefreshClientMetadata', () => { + it('should call tokenOrchestrator.setTokenRefreshClientMetadata', () => { + const clientMetadata = { 'app-version': '1.0.0' }; + + setTokenRefreshClientMetadata(clientMetadata); + + expect( + mockTokenOrchestrator.setTokenRefreshClientMetadata, + ).toHaveBeenCalledWith(clientMetadata); + }); +}); diff --git a/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts b/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts index 8906d8d7eed..3b801b488bd 100644 --- a/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts +++ b/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts @@ -151,4 +151,39 @@ describe('TokenOrchestrator', () => { expect(tokens?.accessToken).toEqual(validAuthTokens.accessToken); }); }); + + describe('setTokenRefreshClientMetadata', () => { + it('should store clientMetadata for token refresh', async () => { + const clientMetadata = { 'app-version': '1.0.0' }; + + mockTokenRefresher.mockResolvedValue({ + accessToken: { payload: {} }, + idToken: { payload: {} }, + clockDrift: 0, + refreshToken: 'newRefreshToken', + username: 'testuser', + }); + + tokenOrchestrator.setTokenRefresher(mockTokenRefresher); + tokenOrchestrator.setAuthTokenStore(mockAuthTokenStore); + tokenOrchestrator.setTokenRefreshClientMetadata(clientMetadata); + + mockAuthTokenStore.loadTokens.mockResolvedValue({ + accessToken: { payload: { exp: 1 } }, + idToken: { payload: { exp: 1 } }, + clockDrift: 0, + refreshToken: 'refreshToken', + username: 'testuser', + }); + mockAuthTokenStore.getLastAuthUser.mockResolvedValue('testuser'); + + await tokenOrchestrator.getTokens({ forceRefresh: true }); + + expect(mockTokenRefresher).toHaveBeenCalledWith( + expect.objectContaining({ + clientMetadata, + }), + ); + }); + }); }); diff --git a/packages/auth/src/providers/cognito/apis/setTokenRefreshClientMetadata.ts b/packages/auth/src/providers/cognito/apis/setTokenRefreshClientMetadata.ts new file mode 100644 index 00000000000..09ab992e868 --- /dev/null +++ b/packages/auth/src/providers/cognito/apis/setTokenRefreshClientMetadata.ts @@ -0,0 +1,17 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { tokenOrchestrator } from '../tokenProvider'; +import type { ClientMetadata } from '../types'; + +/** + * Sets global client metadata for token refresh operations. + * This metadata will be included in all subsequent token refresh requests. + * + * @param clientMetadata - Optional metadata to include with token refresh requests + */ +export function setTokenRefreshClientMetadata( + clientMetadata?: ClientMetadata, +): void { + tokenOrchestrator.setTokenRefreshClientMetadata(clientMetadata); +} diff --git a/packages/auth/src/providers/cognito/index.ts b/packages/auth/src/providers/cognito/index.ts index fc248aaa1de..2cd794266c1 100644 --- a/packages/auth/src/providers/cognito/index.ts +++ b/packages/auth/src/providers/cognito/index.ts @@ -27,6 +27,7 @@ export { rememberDevice } from './apis/rememberDevice'; export { forgetDevice } from './apis/forgetDevice'; export { fetchDevices } from './apis/fetchDevices'; export { autoSignIn } from './apis/autoSignIn'; +export { setTokenRefreshClientMetadata } from './apis/setTokenRefreshClientMetadata'; export { ConfirmResetPasswordInput, ConfirmSignInInput, diff --git a/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts b/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts index 3f8027d2596..ca6d46d8367 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts @@ -19,7 +19,7 @@ import { assertServiceError } from '../../../errors/utils/assertServiceError'; import { AuthError } from '../../../errors/AuthError'; import { oAuthStore } from '../utils/oauth/oAuthStore'; import { addInflightPromise } from '../utils/oauth/inflightPromise'; -import { CognitoAuthSignInDetails } from '../types'; +import { ClientMetadata, CognitoAuthSignInDetails } from '../types'; import { AuthTokenOrchestrator, @@ -32,6 +32,7 @@ import { export class TokenOrchestrator implements AuthTokenOrchestrator { private authConfig?: AuthConfig; + private clientMetadata?: ClientMetadata; tokenStore?: AuthTokenStore; tokenRefresher?: TokenRefresher; inflightPromise: Promise | undefined; @@ -94,6 +95,10 @@ export class TokenOrchestrator implements AuthTokenOrchestrator { return this.tokenRefresher; } + setTokenRefreshClientMetadata(clientMetadata?: ClientMetadata): void { + this.clientMetadata = clientMetadata; + } + async getTokens( options?: FetchAuthSessionOptions, ): Promise< @@ -130,6 +135,7 @@ export class TokenOrchestrator implements AuthTokenOrchestrator { tokens = await this.refreshTokens({ tokens, username, + clientMetadata: options?.clientMetadata ?? this.clientMetadata, }); if (tokens === null) { @@ -147,9 +153,11 @@ export class TokenOrchestrator implements AuthTokenOrchestrator { private async refreshTokens({ tokens, username, + clientMetadata, }: { tokens: CognitoAuthTokens; username: string; + clientMetadata?: ClientMetadata; }): Promise { try { const { signInDetails } = tokens; @@ -157,6 +165,7 @@ export class TokenOrchestrator implements AuthTokenOrchestrator { tokens, authConfig: this.authConfig, username, + clientMetadata, }); newTokens.signInDetails = signInDetails; await this.setTokens({ tokens: newTokens }); diff --git a/packages/auth/src/providers/cognito/tokenProvider/types.ts b/packages/auth/src/providers/cognito/tokenProvider/types.ts index 5f381b42016..2bb0f5ad95d 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/types.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/types.ts @@ -8,16 +8,18 @@ import { TokenProvider, } from '@aws-amplify/core'; -import { CognitoAuthSignInDetails } from '../types'; +import { ClientMetadata, CognitoAuthSignInDetails } from '../types'; export type TokenRefresher = ({ tokens, authConfig, username, + clientMetadata, }: { tokens: CognitoAuthTokens; authConfig?: AuthConfig; username: string; + clientMetadata?: ClientMetadata; }) => Promise; export type AuthKeys = Record; @@ -61,6 +63,7 @@ export interface AuthTokenOrchestrator { clearDeviceMetadata(username?: string): Promise; setOAuthMetadata(metadata: OAuthMetadata): Promise; getOAuthMetadata(): Promise; + setTokenRefreshClientMetadata(clientMetadata?: ClientMetadata): void; } export interface CognitoUserPoolTokenProviderType extends TokenProvider { diff --git a/packages/auth/src/providers/cognito/utils/refreshAuthTokens.ts b/packages/auth/src/providers/cognito/utils/refreshAuthTokens.ts index e29bd460b19..54f30f7a796 100644 --- a/packages/auth/src/providers/cognito/utils/refreshAuthTokens.ts +++ b/packages/auth/src/providers/cognito/utils/refreshAuthTokens.ts @@ -14,15 +14,18 @@ import { assertAuthTokensWithRefreshToken } from '../utils/types'; import { AuthError } from '../../../errors/AuthError'; import { createCognitoUserPoolEndpointResolver } from '../factories'; import { createGetTokensFromRefreshTokenClient } from '../../../foundation/factories/serviceClients/cognitoIdentityProvider'; +import { ClientMetadata } from '../types'; const refreshAuthTokensFunction: TokenRefresher = async ({ tokens, authConfig, username, + clientMetadata, }: { tokens: CognitoAuthTokens; authConfig?: AuthConfig; username: string; + clientMetadata?: ClientMetadata; }): Promise => { assertTokenProviderConfig(authConfig?.Cognito); const { userPoolId, userPoolClientId, userPoolEndpoint } = authConfig.Cognito; @@ -41,6 +44,7 @@ const refreshAuthTokensFunction: TokenRefresher = async ({ ClientId: userPoolClientId, RefreshToken: tokens.refreshToken, DeviceKey: tokens.deviceMetadata?.deviceKey, + ClientMetadata: clientMetadata, }, ); diff --git a/packages/core/src/singleton/Auth/types.ts b/packages/core/src/singleton/Auth/types.ts index 8fa811251b1..a43e6a313d2 100644 --- a/packages/core/src/singleton/Auth/types.ts +++ b/packages/core/src/singleton/Auth/types.ts @@ -66,6 +66,7 @@ export interface TokenProvider { export interface FetchAuthSessionOptions { forceRefresh?: boolean; + clientMetadata?: Record; } export interface AuthTokens { From b20ce29a9eb1e03e99feed3d768ec1dda9f1282b Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Wed, 17 Sep 2025 17:25:56 +0200 Subject: [PATCH 02/10] feat(auth): move clientmetadata to core --- packages/auth/src/providers/cognito/types/models.ts | 2 +- packages/core/src/index.ts | 1 + packages/core/src/singleton/Auth/types.ts | 7 ++++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/auth/src/providers/cognito/types/models.ts b/packages/auth/src/providers/cognito/types/models.ts index 1b113ef1720..8bd212d117a 100644 --- a/packages/auth/src/providers/cognito/types/models.ts +++ b/packages/auth/src/providers/cognito/types/models.ts @@ -38,7 +38,7 @@ export const cognitoHostedUIIdentityProviderMap: Record = /** * Arbitrary key/value pairs that may be passed as part of certain Cognito requests */ -export type ClientMetadata = Record; +export type { ClientMetadata } from '@aws-amplify/core'; /** * Allowed values for preferredChallenge diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index b37829169b3..38db687f425 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -20,6 +20,7 @@ export { OAuthConfig, CognitoUserPoolConfig, JWT, + ClientMetadata, } from './singleton/Auth/types'; export { decodeJWT } from './singleton/Auth/utils'; export { diff --git a/packages/core/src/singleton/Auth/types.ts b/packages/core/src/singleton/Auth/types.ts index a43e6a313d2..dcfce893123 100644 --- a/packages/core/src/singleton/Auth/types.ts +++ b/packages/core/src/singleton/Auth/types.ts @@ -4,6 +4,11 @@ import { StrictUnion } from '../../types'; import { AtLeastOne } from '../types'; +/** + * Arbitrary key/value pairs that may be passed as part of certain Cognito requests + */ +export type ClientMetadata = Record; + // From https://github.com/awslabs/aws-jwt-verify/blob/main/src/safe-json-parse.ts // From https://github.com/awslabs/aws-jwt-verify/blob/main/src/jwt-model.ts interface JwtPayloadStandardFields { @@ -66,7 +71,7 @@ export interface TokenProvider { export interface FetchAuthSessionOptions { forceRefresh?: boolean; - clientMetadata?: Record; + clientMetadata?: ClientMetadata; } export interface AuthTokens { From 6d5c0249f78f5bf1d82dbacb88afd1ba928ea68e Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Wed, 17 Sep 2025 17:36:58 +0200 Subject: [PATCH 03/10] test(auth): combine tests --- .../providers/cognito/refreshToken.test.ts | 32 ++----------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/packages/auth/__tests__/providers/cognito/refreshToken.test.ts b/packages/auth/__tests__/providers/cognito/refreshToken.test.ts index feb41304b0e..c84dfefe0d7 100644 --- a/packages/auth/__tests__/providers/cognito/refreshToken.test.ts +++ b/packages/auth/__tests__/providers/cognito/refreshToken.test.ts @@ -63,6 +63,7 @@ describe('refreshToken', () => { }); it('should refresh token', async () => { + const clientMetadata = { 'app-version': '1.0.0' }; const expectedOutput = { accessToken: decodeJWT(mockAccessToken), idToken: decodeJWT(mockAccessToken), @@ -85,42 +86,13 @@ describe('refreshToken', () => { }, }, username: mockedUsername, + clientMetadata, }); // stringify and re-parse for JWT equality expect(JSON.parse(JSON.stringify(response))).toMatchObject( JSON.parse(JSON.stringify(expectedOutput)), ); - expect(mockGetTokensFromRefreshToken).toHaveBeenCalledWith( - expect.objectContaining({ region: 'us-east-1' }), - expect.objectContaining({ - ClientId: 'aaaaaaaaaaaa', - RefreshToken: mockedRefreshToken, - }), - ); - }); - - it('passes clientMetadata to getTokensFromRefreshToken', async () => { - const clientMetadata = { 'app-version': '1.0.0' }; - - await refreshAuthTokens({ - username: mockedUsername, - tokens: { - accessToken: { payload: {} }, - idToken: { payload: {} }, - clockDrift: 0, - refreshToken: mockedRefreshToken, - username: mockedUsername, - }, - authConfig: { - Cognito: { - userPoolId: 'us-east-1_aaaaaaa', - userPoolClientId: 'aaaaaaaaaaaa', - }, - }, - clientMetadata, - }); - expect(mockGetTokensFromRefreshToken).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-east-1' }), expect.objectContaining({ From 19a7d3a18b97e04b0329cdb27c7df19c0900f184 Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Mon, 29 Sep 2025 15:24:29 +0200 Subject: [PATCH 04/10] feat: add metadata provider --- .../cognito/setClientMetadataProvider.test.ts | 26 +++++++++++++++++++ .../setTokenRefreshClientMetadata.test.ts | 21 --------------- .../cognito/tokenOrchestrator.test.ts | 9 ++++--- .../providers/cognito/tokenProvider.test.ts | 14 ++++++++++ .../apis/setTokenRefreshClientMetadata.ts | 17 ------------ packages/auth/src/providers/cognito/index.ts | 1 - .../CognitoUserPoolsTokenProvider.ts | 7 +++++ .../tokenProvider/TokenOrchestrator.ts | 13 +++++++--- .../providers/cognito/tokenProvider/types.ts | 1 - packages/core/src/index.ts | 1 + packages/core/src/singleton/Auth/types.ts | 11 ++++++++ 11 files changed, 74 insertions(+), 47 deletions(-) create mode 100644 packages/auth/__tests__/providers/cognito/setClientMetadataProvider.test.ts delete mode 100644 packages/auth/__tests__/providers/cognito/setTokenRefreshClientMetadata.test.ts delete mode 100644 packages/auth/src/providers/cognito/apis/setTokenRefreshClientMetadata.ts diff --git a/packages/auth/__tests__/providers/cognito/setClientMetadataProvider.test.ts b/packages/auth/__tests__/providers/cognito/setClientMetadataProvider.test.ts new file mode 100644 index 00000000000..391b356643e --- /dev/null +++ b/packages/auth/__tests__/providers/cognito/setClientMetadataProvider.test.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { cognitoUserPoolsTokenProvider } from '../../../src/providers/cognito/tokenProvider'; + +jest.mock('../../../src/providers/cognito/tokenProvider'); + +const mockCognitoUserPoolsTokenProvider = jest.mocked( + cognitoUserPoolsTokenProvider, +); + +describe('setClientMetadataProvider', () => { + it('should call tokenProvider.setClientMetadataProvider', () => { + const clientMetadataProvider = { + getClientMetadata: () => ({ 'app-version': '1.0.0' }), + }; + + cognitoUserPoolsTokenProvider.setClientMetadataProvider( + clientMetadataProvider, + ); + + expect( + mockCognitoUserPoolsTokenProvider.setClientMetadataProvider, + ).toHaveBeenCalledWith(clientMetadataProvider); + }); +}); diff --git a/packages/auth/__tests__/providers/cognito/setTokenRefreshClientMetadata.test.ts b/packages/auth/__tests__/providers/cognito/setTokenRefreshClientMetadata.test.ts deleted file mode 100644 index 0aab0eb6072..00000000000 --- a/packages/auth/__tests__/providers/cognito/setTokenRefreshClientMetadata.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -import { setTokenRefreshClientMetadata } from '../../../src/providers/cognito/apis/setTokenRefreshClientMetadata'; -import { tokenOrchestrator } from '../../../src/providers/cognito/tokenProvider'; - -jest.mock('../../../src/providers/cognito/tokenProvider'); - -const mockTokenOrchestrator = jest.mocked(tokenOrchestrator); - -describe('setTokenRefreshClientMetadata', () => { - it('should call tokenOrchestrator.setTokenRefreshClientMetadata', () => { - const clientMetadata = { 'app-version': '1.0.0' }; - - setTokenRefreshClientMetadata(clientMetadata); - - expect( - mockTokenOrchestrator.setTokenRefreshClientMetadata, - ).toHaveBeenCalledWith(clientMetadata); - }); -}); diff --git a/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts b/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts index 3b801b488bd..9027400eebc 100644 --- a/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts +++ b/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts @@ -152,9 +152,12 @@ describe('TokenOrchestrator', () => { }); }); - describe('setTokenRefreshClientMetadata', () => { - it('should store clientMetadata for token refresh', async () => { + describe('setClientMetadataProvider', () => { + it('should use clientMetadataProvider for token refresh', async () => { const clientMetadata = { 'app-version': '1.0.0' }; + const clientMetadataProvider = { + getClientMetadata: () => clientMetadata, + }; mockTokenRefresher.mockResolvedValue({ accessToken: { payload: {} }, @@ -166,7 +169,7 @@ describe('TokenOrchestrator', () => { tokenOrchestrator.setTokenRefresher(mockTokenRefresher); tokenOrchestrator.setAuthTokenStore(mockAuthTokenStore); - tokenOrchestrator.setTokenRefreshClientMetadata(clientMetadata); + tokenOrchestrator.setClientMetadataProvider(clientMetadataProvider); mockAuthTokenStore.loadTokens.mockResolvedValue({ accessToken: { payload: { exp: 1 } }, diff --git a/packages/auth/__tests__/providers/cognito/tokenProvider.test.ts b/packages/auth/__tests__/providers/cognito/tokenProvider.test.ts index d12fddb9b0d..a6fbdff6c20 100644 --- a/packages/auth/__tests__/providers/cognito/tokenProvider.test.ts +++ b/packages/auth/__tests__/providers/cognito/tokenProvider.test.ts @@ -389,4 +389,18 @@ describe('device tokens', () => { ), ).toBeUndefined(); }); + + it('should set client metadata provider', () => { + const clientMetadataProvider = { + getClientMetadata: () => ({ 'app-version': '1.0.0' }), + }; + const spy = jest.spyOn( + tokenStore.tokenOrchestrator, + 'setClientMetadataProvider', + ); + + tokenStore.setClientMetadataProvider(clientMetadataProvider); + + expect(spy).toHaveBeenCalledWith(clientMetadataProvider); + }); }); diff --git a/packages/auth/src/providers/cognito/apis/setTokenRefreshClientMetadata.ts b/packages/auth/src/providers/cognito/apis/setTokenRefreshClientMetadata.ts deleted file mode 100644 index 09ab992e868..00000000000 --- a/packages/auth/src/providers/cognito/apis/setTokenRefreshClientMetadata.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -import { tokenOrchestrator } from '../tokenProvider'; -import type { ClientMetadata } from '../types'; - -/** - * Sets global client metadata for token refresh operations. - * This metadata will be included in all subsequent token refresh requests. - * - * @param clientMetadata - Optional metadata to include with token refresh requests - */ -export function setTokenRefreshClientMetadata( - clientMetadata?: ClientMetadata, -): void { - tokenOrchestrator.setTokenRefreshClientMetadata(clientMetadata); -} diff --git a/packages/auth/src/providers/cognito/index.ts b/packages/auth/src/providers/cognito/index.ts index 2cd794266c1..fc248aaa1de 100644 --- a/packages/auth/src/providers/cognito/index.ts +++ b/packages/auth/src/providers/cognito/index.ts @@ -27,7 +27,6 @@ export { rememberDevice } from './apis/rememberDevice'; export { forgetDevice } from './apis/forgetDevice'; export { fetchDevices } from './apis/fetchDevices'; export { autoSignIn } from './apis/autoSignIn'; -export { setTokenRefreshClientMetadata } from './apis/setTokenRefreshClientMetadata'; export { ConfirmResetPasswordInput, ConfirmSignInInput, diff --git a/packages/auth/src/providers/cognito/tokenProvider/CognitoUserPoolsTokenProvider.ts b/packages/auth/src/providers/cognito/tokenProvider/CognitoUserPoolsTokenProvider.ts index 43f0f8a2d8c..ca4a300d598 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/CognitoUserPoolsTokenProvider.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/CognitoUserPoolsTokenProvider.ts @@ -4,6 +4,7 @@ import { AuthConfig, AuthTokens, + ClientMetadataProvider, FetchAuthSessionOptions, KeyValueStorageInterface, defaultStorage, @@ -38,6 +39,12 @@ export class CognitoUserPoolsTokenProvider this.authTokenStore.setKeyValueStorage(keyValueStorage); } + setClientMetadataProvider( + clientMetadataProvider: ClientMetadataProvider, + ): void { + this.tokenOrchestrator.setClientMetadataProvider(clientMetadataProvider); + } + setAuthConfig(authConfig: AuthConfig) { this.authTokenStore.setAuthConfig(authConfig); this.tokenOrchestrator.setAuthConfig(authConfig); diff --git a/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts b/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts index ca6d46d8367..90c70e7c285 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts @@ -3,6 +3,7 @@ import { AuthConfig, AuthTokens, + ClientMetadataProvider, CognitoUserPoolConfig, FetchAuthSessionOptions, Hub, @@ -32,7 +33,7 @@ import { export class TokenOrchestrator implements AuthTokenOrchestrator { private authConfig?: AuthConfig; - private clientMetadata?: ClientMetadata; + private clientMetadataProvider?: ClientMetadataProvider; tokenStore?: AuthTokenStore; tokenRefresher?: TokenRefresher; inflightPromise: Promise | undefined; @@ -95,8 +96,10 @@ export class TokenOrchestrator implements AuthTokenOrchestrator { return this.tokenRefresher; } - setTokenRefreshClientMetadata(clientMetadata?: ClientMetadata): void { - this.clientMetadata = clientMetadata; + setClientMetadataProvider( + clientMetadataProvider: ClientMetadataProvider, + ): void { + this.clientMetadataProvider = clientMetadataProvider; } async getTokens( @@ -135,7 +138,9 @@ export class TokenOrchestrator implements AuthTokenOrchestrator { tokens = await this.refreshTokens({ tokens, username, - clientMetadata: options?.clientMetadata ?? this.clientMetadata, + clientMetadata: + options?.clientMetadata ?? + this.clientMetadataProvider?.getClientMetadata(), }); if (tokens === null) { diff --git a/packages/auth/src/providers/cognito/tokenProvider/types.ts b/packages/auth/src/providers/cognito/tokenProvider/types.ts index 2bb0f5ad95d..c1d2c47badf 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/types.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/types.ts @@ -63,7 +63,6 @@ export interface AuthTokenOrchestrator { clearDeviceMetadata(username?: string): Promise; setOAuthMetadata(metadata: OAuthMetadata): Promise; getOAuthMetadata(): Promise; - setTokenRefreshClientMetadata(clientMetadata?: ClientMetadata): void; } export interface CognitoUserPoolTokenProviderType extends TokenProvider { diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 38db687f425..d65eac33003 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -21,6 +21,7 @@ export { CognitoUserPoolConfig, JWT, ClientMetadata, + ClientMetadataProvider, } from './singleton/Auth/types'; export { decodeJWT } from './singleton/Auth/utils'; export { diff --git a/packages/core/src/singleton/Auth/types.ts b/packages/core/src/singleton/Auth/types.ts index dcfce893123..8746a658b41 100644 --- a/packages/core/src/singleton/Auth/types.ts +++ b/packages/core/src/singleton/Auth/types.ts @@ -9,6 +9,16 @@ import { AtLeastOne } from '../types'; */ export type ClientMetadata = Record; +/** + * Interface for providing client metadata for Cognito operations + */ +export interface ClientMetadataProvider { + /** + * Returns client metadata for token refresh operations + */ + getClientMetadata(): ClientMetadata; +} + // From https://github.com/awslabs/aws-jwt-verify/blob/main/src/safe-json-parse.ts // From https://github.com/awslabs/aws-jwt-verify/blob/main/src/jwt-model.ts interface JwtPayloadStandardFields { @@ -51,6 +61,7 @@ export interface AuthSession { export interface LibraryAuthOptions { tokenProvider?: TokenProvider; credentialsProvider?: CredentialsAndIdentityIdProvider; + clientMetadataProvider?: ClientMetadataProvider; } export interface Identity { From d81eaf32e44b403ce6928f98a806dd36cf41e5ea Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Mon, 29 Sep 2025 15:30:33 +0200 Subject: [PATCH 05/10] chore: remove wrong test --- .../providers/cognito/tokenProvider.test.ts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/packages/auth/__tests__/providers/cognito/tokenProvider.test.ts b/packages/auth/__tests__/providers/cognito/tokenProvider.test.ts index a6fbdff6c20..d12fddb9b0d 100644 --- a/packages/auth/__tests__/providers/cognito/tokenProvider.test.ts +++ b/packages/auth/__tests__/providers/cognito/tokenProvider.test.ts @@ -389,18 +389,4 @@ describe('device tokens', () => { ), ).toBeUndefined(); }); - - it('should set client metadata provider', () => { - const clientMetadataProvider = { - getClientMetadata: () => ({ 'app-version': '1.0.0' }), - }; - const spy = jest.spyOn( - tokenStore.tokenOrchestrator, - 'setClientMetadataProvider', - ); - - tokenStore.setClientMetadataProvider(clientMetadataProvider); - - expect(spy).toHaveBeenCalledWith(clientMetadataProvider); - }); }); From 5ab039f9e59a7fc0b8502a2a6ab494635a4f7889 Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Mon, 29 Sep 2025 15:32:28 +0200 Subject: [PATCH 06/10] feat: remove it from libraryAuthOptions --- packages/core/src/singleton/Auth/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core/src/singleton/Auth/types.ts b/packages/core/src/singleton/Auth/types.ts index 8746a658b41..2c09501831e 100644 --- a/packages/core/src/singleton/Auth/types.ts +++ b/packages/core/src/singleton/Auth/types.ts @@ -61,7 +61,6 @@ export interface AuthSession { export interface LibraryAuthOptions { tokenProvider?: TokenProvider; credentialsProvider?: CredentialsAndIdentityIdProvider; - clientMetadataProvider?: ClientMetadataProvider; } export interface Identity { From 1590dbd9b80e5d288657622cf567230ff3e00e55 Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Mon, 29 Sep 2025 15:47:03 +0200 Subject: [PATCH 07/10] feat: switched from interface to function --- .../providers/cognito/setClientMetadataProvider.test.ts | 5 ++--- .../providers/cognito/tokenOrchestrator.test.ts | 4 +--- .../providers/cognito/tokenProvider/TokenOrchestrator.ts | 3 +-- packages/core/src/singleton/Auth/types.ts | 9 ++------- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/packages/auth/__tests__/providers/cognito/setClientMetadataProvider.test.ts b/packages/auth/__tests__/providers/cognito/setClientMetadataProvider.test.ts index 391b356643e..3d3bbd3bc26 100644 --- a/packages/auth/__tests__/providers/cognito/setClientMetadataProvider.test.ts +++ b/packages/auth/__tests__/providers/cognito/setClientMetadataProvider.test.ts @@ -11,9 +11,8 @@ const mockCognitoUserPoolsTokenProvider = jest.mocked( describe('setClientMetadataProvider', () => { it('should call tokenProvider.setClientMetadataProvider', () => { - const clientMetadataProvider = { - getClientMetadata: () => ({ 'app-version': '1.0.0' }), - }; + const clientMetadataProvider = () => + Promise.resolve({ 'app-version': '1.0.0' }); cognitoUserPoolsTokenProvider.setClientMetadataProvider( clientMetadataProvider, diff --git a/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts b/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts index 9027400eebc..de276fafd5a 100644 --- a/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts +++ b/packages/auth/__tests__/providers/cognito/tokenOrchestrator.test.ts @@ -155,9 +155,7 @@ describe('TokenOrchestrator', () => { describe('setClientMetadataProvider', () => { it('should use clientMetadataProvider for token refresh', async () => { const clientMetadata = { 'app-version': '1.0.0' }; - const clientMetadataProvider = { - getClientMetadata: () => clientMetadata, - }; + const clientMetadataProvider = () => Promise.resolve(clientMetadata); mockTokenRefresher.mockResolvedValue({ accessToken: { payload: {} }, diff --git a/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts b/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts index 90c70e7c285..ccd5b98987a 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts @@ -139,8 +139,7 @@ export class TokenOrchestrator implements AuthTokenOrchestrator { tokens, username, clientMetadata: - options?.clientMetadata ?? - this.clientMetadataProvider?.getClientMetadata(), + options?.clientMetadata ?? (await this.clientMetadataProvider?.()), }); if (tokens === null) { diff --git a/packages/core/src/singleton/Auth/types.ts b/packages/core/src/singleton/Auth/types.ts index 2c09501831e..18dafd9761b 100644 --- a/packages/core/src/singleton/Auth/types.ts +++ b/packages/core/src/singleton/Auth/types.ts @@ -10,14 +10,9 @@ import { AtLeastOne } from '../types'; export type ClientMetadata = Record; /** - * Interface for providing client metadata for Cognito operations + * Function type for providing client metadata for Cognito operations */ -export interface ClientMetadataProvider { - /** - * Returns client metadata for token refresh operations - */ - getClientMetadata(): ClientMetadata; -} +export type ClientMetadataProvider = () => Promise; // From https://github.com/awslabs/aws-jwt-verify/blob/main/src/safe-json-parse.ts // From https://github.com/awslabs/aws-jwt-verify/blob/main/src/jwt-model.ts From a2886a61cefd954e1947fb748e2f42224ab8c5b6 Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Tue, 30 Sep 2025 14:38:01 +0200 Subject: [PATCH 08/10] chore: remove unnessecary test --- .../cognito/setClientMetadataProvider.test.ts | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 packages/auth/__tests__/providers/cognito/setClientMetadataProvider.test.ts diff --git a/packages/auth/__tests__/providers/cognito/setClientMetadataProvider.test.ts b/packages/auth/__tests__/providers/cognito/setClientMetadataProvider.test.ts deleted file mode 100644 index 3d3bbd3bc26..00000000000 --- a/packages/auth/__tests__/providers/cognito/setClientMetadataProvider.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -import { cognitoUserPoolsTokenProvider } from '../../../src/providers/cognito/tokenProvider'; - -jest.mock('../../../src/providers/cognito/tokenProvider'); - -const mockCognitoUserPoolsTokenProvider = jest.mocked( - cognitoUserPoolsTokenProvider, -); - -describe('setClientMetadataProvider', () => { - it('should call tokenProvider.setClientMetadataProvider', () => { - const clientMetadataProvider = () => - Promise.resolve({ 'app-version': '1.0.0' }); - - cognitoUserPoolsTokenProvider.setClientMetadataProvider( - clientMetadataProvider, - ); - - expect( - mockCognitoUserPoolsTokenProvider.setClientMetadataProvider, - ).toHaveBeenCalledWith(clientMetadataProvider); - }); -}); From c413a5dafd39a09c2dc47b9cc73896085664c475 Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Tue, 30 Sep 2025 14:43:05 +0200 Subject: [PATCH 09/10] chore: make variable public --- .../src/providers/cognito/tokenProvider/TokenOrchestrator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts b/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts index ccd5b98987a..851db00846f 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/TokenOrchestrator.ts @@ -33,7 +33,7 @@ import { export class TokenOrchestrator implements AuthTokenOrchestrator { private authConfig?: AuthConfig; - private clientMetadataProvider?: ClientMetadataProvider; + clientMetadataProvider?: ClientMetadataProvider; tokenStore?: AuthTokenStore; tokenRefresher?: TokenRefresher; inflightPromise: Promise | undefined; From 562abea670d9d854d82fc50b12acac6e77f797f2 Mon Sep 17 00:00:00 2001 From: Michael Sober Date: Tue, 30 Sep 2025 15:36:47 +0200 Subject: [PATCH 10/10] feat: add setter function to type --- packages/auth/src/providers/cognito/tokenProvider/types.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/auth/src/providers/cognito/tokenProvider/types.ts b/packages/auth/src/providers/cognito/tokenProvider/types.ts index c1d2c47badf..4ac6973b60e 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/types.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/types.ts @@ -3,6 +3,7 @@ import { AuthConfig, AuthTokens, + ClientMetadataProvider, FetchAuthSessionOptions, KeyValueStorageInterface, TokenProvider, @@ -68,6 +69,9 @@ export interface AuthTokenOrchestrator { export interface CognitoUserPoolTokenProviderType extends TokenProvider { setKeyValueStorage(keyValueStorage: KeyValueStorageInterface): void; setAuthConfig(authConfig: AuthConfig): void; + setClientMetadataProvider( + clientMetadataProvider: ClientMetadataProvider, + ): void; } export type CognitoAuthTokens = AuthTokens & {