Skip to content

Commit 3686ee5

Browse files
committed
feat(trpc-react): cache sigv4 credentials
Instead of making requests to the identity pool for fresh credentials on every api call in the react trpc client, we cache credentials (in memory) until just before they expire re #49
1 parent c1b7061 commit 3686ee5

File tree

3 files changed

+21
-3
lines changed

3 files changed

+21
-3
lines changed

packages/nx-plugin/src/trpc/react/files/src/hooks/useSigV4.tsx.template

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,31 @@
11
import { AwsClient } from 'aws4fetch';
22
import { CognitoIdentityClient } from '@aws-sdk/client-cognito-identity';
33
import { fromCognitoIdentityPool } from '@aws-sdk/credential-provider-cognito-identity';
4-
import { useCallback } from 'react';
4+
import { useCallback, useState } from 'react';
55
import { useAuth } from 'react-oidc-context';
66
import { useRuntimeConfig } from './useRuntimeConfig';
7+
import { AwsCredentialIdentity, AwsCredentialIdentityProvider } from '@smithy/types';
8+
9+
// Credential expiration grace time before considering credentials as expired
10+
const CREDENTIAL_EXPIRY_OFFSET_MILLIS = 30 * 1000;
711

812
export const useSigV4 = () => {
913
const { cognitoProps } = useRuntimeConfig();
1014
const { user } = useAuth();
1115

16+
const [cachedCredentials, setCachedCredentials] = useState<{ [key: string]: AwsCredentialIdentity }>({});
17+
18+
const withCachedCredentials = useCallback(async (provider: AwsCredentialIdentityProvider, ...cacheKeys: string[]): Promise<AwsCredentialIdentity> => {
19+
const key = `sigv4/${cacheKeys.join('/')}`;
20+
const cachedCreds = cachedCredentials[key];
21+
if (cachedCreds && cachedCreds.expiration && cachedCreds.expiration.getTime() > Date.now() + CREDENTIAL_EXPIRY_OFFSET_MILLIS) {
22+
return cachedCreds;
23+
}
24+
const credentials = await provider();
25+
setCachedCredentials((prev) => ({ ...prev, [key]: credentials }));
26+
return credentials;
27+
}, [cachedCredentials, setCachedCredentials]);
28+
1229
return useCallback(
1330
async (input: RequestInfo | URL, init?: RequestInit | undefined) => {
1431
if (!cognitoProps) {
@@ -29,7 +46,7 @@ export const useSigV4 = () => {
2946
const cognitoidentity = new CognitoIdentityClient({
3047
credentials: credentialsFromCognitoIdentityPool,
3148
});
32-
const credential = await cognitoidentity.config.credentials();
49+
const credential = await withCachedCredentials(cognitoidentity.config.credentials, cognitoProps.identityPoolId, user.profile.sub);
3350
const awsClient = new AwsClient(credential);
3451
return awsClient.fetch(input, init);
3552
},

packages/nx-plugin/src/trpc/react/generator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ export async function reactGenerator(
388388
? ['oidc-client-ts', 'react-oidc-context']
389389
: []) as any),
390390
]),
391-
{},
391+
withVersions(['@smithy/types']),
392392
);
393393
await formatFilesInSubtree(tree);
394394
return () => {

packages/nx-plugin/src/utils/versions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const VERSIONS = {
2020
'@trpc/client': '11.0.0-rc.700',
2121
'@trpc/server': '11.0.0-rc.700',
2222
'@types/aws-lambda': '^8.10.145',
23+
'@smithy/types': '^4.1.0',
2324
aws4fetch: '^1.0.20',
2425
'aws-cdk': '^2.166.0',
2526
'aws-cdk-lib': '^2.166.0',

0 commit comments

Comments
 (0)