2

I am trying to upload a file to AWS S3 using aws-sdk v3 from a Nuxt app's Vue Component.

Here's how I upload it.

<script>
export default {
...
methods: {
onSubmit(event) {
    event.preventDefault()
    this.addPhoto()
},
addPhoto() {
  // Load the required clients and packages
  const { CognitoIdentityClient } = require('@aws-sdk/client-cognito-identity')
  const { fromCognitoIdentityPool } = require('@aws-sdk/credential-provider-cognito-identity')
  const {
    S3Client,
    PutObjectCommand,
    ListObjectsCommand,
    DeleteObjectCommand,
  } = require('@aws-sdk/client-s3')

  const REGION = 'us-east-1' // REGION
  const albumBucketName = 'samyojya-1'
  const IdentityPoolId = 'XXXXXXX'

  const s3 = new S3Client({
    region: REGION,
    credentials: {
      accessKeyId: this.$config.CLIENT_ID,
      secretAccessKey: this.$config.CLIENT_SECRET,
      sessionToken: localStorage.getItem('accessToken'),
    },
  })

  var file = this.formFields[0].fieldName
  var fileName = this.formFields[0].fieldName.name
  var photoKey = 'user-dp/' + fileName
  var s3Response = s3.send(
    new PutObjectCommand({
      Bucket: albumBucketName,
      Key: photoKey,
      Body: file,
    }),
  )
  s3Response
    .then((response) => {
      console.log('Successfully uploaded photo.' + JSON.stringify(response))
    })
    .catch((error) => {
      console.log(
        'There was an error uploading your photo: Error stacktrace' + JSON.stringify(error.message),
      )
      const { requestId, cfId, extendedRequestId } = error.$metadata
      console.log({ requestId, cfId, extendedRequestId })
    })
},

...

}
</script>

The issue now is that the browser complains about CORS.

CORS error while s3 upload

This is my CORS configuration on AWS S3

s3 CORS Configuration

  1. I'm suspecting something while creating the upload request using SDK. (I'm open to use an API that is better than what I'm using).
  2. Nuxt setting that allows CORS.
  3. Something else on S3 CORS config at permissions
  4. Network tab on chrome dev tools shows Internal Server Error (500) for prefetch. (Don't know why we see 2 entries here) Network tab snapshot 1 without OPTIONS HTTP verb. This is called first Network tab snapshot 2 with OPTIONS HTTP verb Appreciate any pointers on how to debug this.
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Naveen Karnam
  • 433
  • 2
  • 9
  • 26

5 Answers5

5

I was having the same issue today. The S3 logs were saying it returned a 200 code response, but Chrome was seeing a 500 response. In Safari, the error showed up as:

received 'us-west-1'; expected 'eu-west-1'

Adding region: 'eu-west-1' (i.e. the region where the bucked was created)to the parameters when creating the S3 service solved the issue for me.

https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-region.html#setting-region-constructor

BenJ
  • 51
  • 1
  • 4
  • Thanks for sharing this. I just noticed that my s3 bucket was indeed pointing to a different region. Now my error changed from 500 to 403. That's still a progress I would say. Waiting for access logs to appear to debug further. Will revert. – Naveen Karnam Apr 02 '21 at 18:30
  • Here's what I see on the s3 access logs... "a1bc55fcae7ba9acea6e082e6a6df67be958670c5a007dfa28aa6f0470f9e19e samyojya-1 [06/May/2021:10:46:44 +0000] 49.206.4.117 - KSM4CMAWAYZC7CY2 REST.OPTIONS.PREFLIGHT - "OPTIONS / HTTP/1.1" 403 AccessForbidden 514 - 19 - "https://dev.samyojya.com:3000/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36" - c5uqa8Cs0mCqUYp5G5uBRWwGyLov5g6mBcEB7RPp3krNmQywg4wTI+xLp+ldO2HwvifksZ6PAio= - ECDHE-RSA-AES128-GCM-SHA256 - samyojya-1.s3.ap-south-1.amazonaws.com TLSv1.2" – Naveen Karnam May 06 '21 at 16:06
2

In the bucket policy use this

 {
"Version": "2008-10-17",
"Statement": [
    {
        "Effect": "Allow",
        "Principal": {
            "AWS": "*"
        },
        "Action": [
            "s3:GetObjectAcl",
            "s3:GetObject",
            "s3:PutObject",
            "s3:PutObjectAcl",
            "s3:ListMultipartUploadParts"
        ],
        "Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*",
        "Condition": {
            "StringLike": {
                "aws:Referer": "https://example/*"
            }
        }
    }
]}

and use the region of your bucket

const s3 = new aws.S3({
    apiVersion: 'latest',
    accessKeyId: process.env.AWS_ACCESS_KEY_ID_CUSTOM,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY_CUSTOM,
    region: 'us-west-1',
})

enter image description here

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
  • I tried changing the bucket policy. Seeing the same error. @Gabriel. aws.S3 is looking like v2 - the older version. I am using v3. – Naveen Karnam May 06 '21 at 10:12
1

I am having the same problem, but according to the docs you should be using Cognito Identity to access the bucket. Only in V3 for clients to be able to access the buckets from the browser you must use Cognito Identity to authenticate users in order to have access to bucket/object commands. Currently trying to implement, so I am not 100% how to do it just the process. Feel free to take a look. I hope this helps. ~~~~~~~~~~~~~~~~~~~~~~~~~~ | Cognito SDK Link: | https://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html | Example: | https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-browser-credentials-cognito.html

dbob486
  • 11
  • 2
  • This is a good suggestion, I feel. I will give it a shot. My only challenge here is to find out the "Logins" provider object for Cognito User pool Client in the Cognito Identity Object. – Naveen Karnam Mar 05 '21 at 08:35
  • Please feel free to message me back if you figure it out. I am still struggling with it so it would be nice to get some insight if u figure it out. Thanks! – dbob486 Mar 05 '21 at 22:23
0

The error needs to be fixed on the backend, since it's CORS. It's clearly states a missing header of Access-Control-Allow-Origin.
So, checking it in the official AWS docs gives you the answer: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html

kissu
  • 40,416
  • 14
  • 65
  • 133
  • You are right about the backend part @kissu. The backend here is aws s3. aws-sdk's s3 client calls s3 server. s3 server needs to return the header as configured in the v3 bucket permissions - CORS policy. Weird! :-/ – Naveen Karnam Mar 04 '21 at 15:35
  • So yeah, go to your backend dashboard and edit it to allow for the required header ! – kissu Mar 04 '21 at 17:22
  • I got you now. I reset the "AllowedHeaders" parameter to 'Access-Control-Allow-Origin' in s3 bucket permissions CORS policy and tried upload. It doesn't work. – Naveen Karnam Mar 04 '21 at 18:58
  • I enabled server access logs on s3 bucket. Will see if something interesting shows up there. It looks like it takes some time to collect and pass on the logs. – Naveen Karnam Mar 04 '21 at 23:02
0

I was doing multiple things wrongly here. Every answer on this post helped me make a little progress while debugging. Can't thank you enough!

  1. My bucket policy was not using role-based ALLOW/DENY that has to correspond to authenticated role on my cognito identity pool.
  2. Needed to rightly configure the Authentication provider as Cognito Userpool.
  3. Making sure the region is right. Cognito region could be different from S3 region.
  4. Make sure CORS policy includes relevant information like "Access-Control-Allow-Origin".
  5. Double check the token includes the right credentials. This comes very handy cognito decode-verify
  6. Was stand-alone testing from the browser. But this is not a good approach. Use an API server to take the file and push to S3 from there.
Naveen Karnam
  • 433
  • 2
  • 9
  • 26