How to refresh AWS SDK JS V3 client credentials using a credential provider?

949 Views Asked by At

I am using the AWS SDK JS V3 in the browser in an Angular app along with Cognito to handle user authentication.

I am able to successfully instantiate the CognitoIdentityProviderClient using the fromCognitoIdentityPool credential provider like so:

this.cognitoClient = new CognitoIdentityProviderClient({
      region: environment.cognito.region,
      credentials: fromCognitoIdentityPool({
        clientConfig: { region: environment.cognito.region },
        identityPoolId: environment.cognito.identityPoolId,
        logins: {
          [`cognito-idp.${environment.cognito.region}.amazonaws.com/${environment.cognito.userPoolId}`]: this.authService.getIdToken()! // getIdToken() returns a JWT string for the IDToken from the CognitoUserSession object.
        }
      })
    });

and make requests (such as the ListUsersCommand) as usual.

However, after an hour of idle time, the IDToken provided by Cognito expires and any subsequent requests throw a NotAuthorizedException: "Invalid login token." error.

My expectation is that I only need to instantiate the client once and then either it will automatically handle the refresh or I will need to manually trigger the refresh. I have tried a few different solutions, including re-instantiating the client, but I don't think any of them handle the refresh properly and efficiently.

I have already looked at How to refresh credentials in the AWS JS SDK v3?, but the answer parrots Use Case 32 located in the amazon-cognito-identity-js documentation, which refers to the AWS SDK JS V2 implementation.

In short, I am looking for an example of how to properly refresh credentials for an AWS SDK JS V3 client that uses the fromCognitoIdentityPool credential provider.

1

There are 1 best solutions below

0
On

Interestingly enough, I came across your question when exploring how to use this function related to Amazon Location services. They have a great example of how to do exactly this here. So reduce what they have to the relevant bit:

const credentialsProvider = fromCognitoIdentityPool({
    identityPoolId,
    clientConfig: {
        region,
    },
});

// Defined here to be accessible elsewhere outside the refresh function
let credentials: AwsCredentialIdentity;

async function refreshCredentials() {
    credentials = await credentialsProvider();

    // default to 1 hour if credentials does not have expiration field
    let timeToRefresh = 3600000;
    if (credentials.expiration) {
        timeToRefresh = credentials.expiration.getTime() - new Date().getTime();
    }

    // timeToRefresh minus 1 minute to give some time for the actual refresh to happen.
    setTimeout(refreshCredentials, timeToRefresh - 60000);
}

await refreshCredentials();