Optimizing Credential Configuration in AWS SDK for JavaScript v3: Understanding Cache Mechanisms and Best Practices
Tags: node, javascript, aws, awssdk
Published: 2024-06-03 15:04:49

---
title: Optimizing Credential Configuration in AWS SDK for JavaScript v3: Understanding Cache Mechanisms and Best Practices
published: true
tags:
  - NodeJS
  - JavaScript
  - AWS
  - AWSSDK
---
This article is a translation of https://zenn.dev/tilfin/articles/56f8dc56b83901.

## Background

The AWS SDK for JavaScript v3 introduced a significant shift in client configuration compared to v2. While v2 allowed for global SDK settings, v3 adopts a per-client instance runtime configuration approach. Consequently, credential retrieval, which was internally cached in v2 even with randomly generated clients for each AWS resource, now presents potential challenges in v3 with frequent credential requests.

## Delving into Credential Retrieval Logic

The simplest approach involves directly setting AWS access and secret keys as `credentials` in the constructor arguments of AWS resource clients. However, this method is not ideal for real-world application development. Applications deployed on EC2 or ECS typically retrieve credentials from instance or container metadata services, while Lambda functions often obtain them via environment variables. The AWS SDK v3 implements these credential supply logics as **Credential Providers**.

You can also specify a **Credential Provider** for the client's `credentials`. Details are described on the following page:
https://github.com/aws/aws-sdk-js-v3/tree/main/packages/credential-providers

If nothing is specified for `credentials`, the function set in `credentialDefaultProvider` is executed first to generate a **Credential Provider**, which is then used as `credentials`. The default `credentialDefaultProvider` is `defaultProvider`. It attempts various acquisition methods. By using this method, you can automatically refer to `~/.aws/credentials` in a local environment and metadata in a deployed environment.

To explicitly specify the implementation of `defaultProvider`, use `fromNodeProviderChain`.

## Credential Caching Mechanism

Credential retrieval occurs each time a client invokes a command. However, **Credential Providers, which implement the various retrieval logics provided by the AWS SDK, do not have a caching mechanism. The only exception is the `memoize` function of `@smithy/property-provider` used internally by `defaultProvider`.** Furthermore, **the re-acquisition logic for time-limited credentials, including session tokens, is also implemented only here.**

https://github.com/aws/aws-sdk-js-v3/blob/main/packages/credential-provider-node/src/defaultProvider.ts#L59

https://github.com/smithy-lang/smithy-typescript/blob/main/packages/property-provider/src/memoize.ts#L46

## What are the Best Practices?

Based on the insights so far, in most cases where you are implementing an application that operates within the same AWS account, "using `defaultProvider`", or "specifying nothing", is the best approach. However, there is a potential pitfall here.

As mentioned at the beginning, in v3, since each client has a different **Credential Provider**, caching is also done on a per-client basis. For example, in a batch processing loop where the code "creates a client and retrieves an item", there is a possibility that credential acquisition will fail. Below is an issue where an error occurred because the access limit of EC2's metadata endpoint was reached.

https://github.com/aws/aws-sdk-js-v3/issues/4867

As a workaround, the issue's comments suggest caching (reusing) the instances of each AWS client themselves. However, in applications that rely on many AWS services and where command transmissions to them occur intensively, this may not be avoidable. There is also an improvement proposal for this.

https://github.com/aws/aws-sdk-js-v3/issues/4612

## Conclusion

Currently, the best practice is to reuse `defaultProvider`. Since `fromNodeProviderChain` is provided by the SDK, generate it at the module level as shown below and reuse it.

```
import { fromNodeProviderChain } from "@aws-sdk/credential-providers";

export const credentialProvider = fromNodeProviderChain();
```

```
new S3Client({ credentials: credentialProvider });

new DynamoDBClient({ credentials: credentialProvider });
```

This will prevent the retrieval process from being concentrated internally.

### References

https://zenn.dev/luma/articles/bd3c59b3d7682d