0

I have an issue with the S3 Client from aws sdk v3 :

If i use the S3Client, as specified in the documentation, with the credentials provided using the environent variables, i get the error The AWS Access Key Id you provided does not exist in our records.

At first i thought it was because i didn't use the correct AWS_ACCESS_KEY_ID, but adding this line just after the client initialization fixed the issue, and logged the correct values :

s3.config.credentials().then(console.log)

What bother me the most is the fact that if i call this line anywhere else (ie: in a async function), it does not fix the issue.

  • Why does this async function call fix the rest of the execution ?
  • Does it only fix the client temporarly ? (the client stay instantiated for multiple function calls)
  • Can the promise end to late : after the fist call of the client ?
  • Why doesn't it work when called right before an s3 call (with or without await) ?

Here is my code :

const s3Config: S3ClientConfig = {}
s3Config.endpoint = new HttpRequest({...} as Endpoint) // used with a local s3 server
const s3 = new S3Client(s3Config);

// this is the hack
s3.config.credentials().then(console.log)

export const upload = async (...) => {
    // here it does not work
    // await s3.config.credentials().then(console.log)

    const streamUpload = new Upload({client: s3,...})
    return await streamUpload.done()
}


export const getTempLink = async (...) => {
    // here it does not work
    // await s3.config.credentials().then(console.log)

    //* Get the pre-signed url
    const command = new GetObjectCommand({Bucket,Key})
    return await getSignedUrl(s3 as any, command as any, { expiresIn })
}

Thanks for your help !

Pierre Lezan
  • 120
  • 1
  • 10

2 Answers2

1

I got a similar issue with that

First was the difference between the aws-sdk vs aws-sdk/client-s3

My problem was that in the .env file the key names are like this

ACCESS_KEY_ID, 
SECRET_ACCESS_KEY, 
AWS_SESSION_TOKEN

That don't work, so I change the name like following and ready to go. It took the credentials.

AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY,
AWS_SESSION_TOKEN,

Remember that AWS has a chain of precedence for credentials

DSDmark
  • 1,045
  • 5
  • 11
  • 25
Programmer89
  • 145
  • 3
  • 15
  • I already tried this but it was something else. Thanks for your anwser. I will write an answer explaining what realy fixed my issue – Pierre Lezan Feb 06 '23 at 09:40
1

Here are the few things I found to answer my questions :

As mentioned in the question the line who makes it work is

await s3.config.credentials()

Why does this async function call fix the rest of the execution?

As answered here using service constructors you can have multiple AWS configs. Also, as Programmer89 precised, the chain of precedence matter, but there is a catch :
The AWS clients don't load the config right away, but only when it's necessary.

Using the config.credentials() function ensures that the config is loaded immediately.

Why doesn't it work when called right before an s3 call (with or without await)?

This config needs to be loaded right away because the same AWS SDK is used with other configs (using custom DynamoDB and S3 endpoints for local tests).

If called anytime after, it seems to use the last environment variable used with that SDK and not the one available at the time of calling the constructor.

Does it only fix the client temporarily? (the client stays instantiated for multiple function calls)

I'm not sure, it may or may not but we only had that issue for local tests.

In production, those processes are better separated. Locally the client does not stay instantiated for more than one call so I did not look any further.

Can the Promise end too late: after the first call from the client?

It doesn't seem to matter as long as the client started to load the config (ie: the Promise started).

I hope the answers I found here could help someone else having the same issue.

Pierre Lezan
  • 120
  • 1
  • 10