Search code examples
amazon-web-servicesamazon-s3corsfetchmultipartform-data

Uploading formData file from client to S3 using createPresignedPost or getPresignedUrl fails due to CORS


I'm using a React web app and trying to upload a file to AWS S3.
I've tried everything both locally (localhost:3000) and when deployed to production (Vercel serverless functions).

I first use a fetch to retrieve a presigned url for the file upload, which works perfectly:

module.exports = async (req, res) => {
    let {fileName, fileType} = req.body;
    const post = await s3.createPresignedPost({
        Bucket: BUCKET_NAME,
        Fields: {
            key: fileName
        },
        ContentType: fileType,
        Expires: 60
    });
    res.status(200).json(post);

Then, in the second fetch:

await fetch(url, {method: 'POST', body: formData}

I'm getting:

fetch has been blocked by CORS policy: No 'Access-Control-Allow-Origin'

I have set up the Permissions -> CORS json in the bucket configuration correctly:

[
    {
        "AllowedHeaders": [
            "*",
            "Content-*"
        ],
        "AllowedMethods": [
            "HEAD",
            "GET",
            "PUT",
            "POST",
            "DELETE"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "*"
        ]
    }
]

I also verified the bucket name in my code.

I've tried:

  • Both getPresignedUrl & createPresignedPost to generate the url
  • Both PUT & POST requests
  • Setting headers (Content-Type, x-amz-acl) in the fetch request
  • Using different CORS jsons, allowing all origins, expose different headers, allowing all methods (including HEAD, allowing different headers (like "Content-*")
  • Configuring different users with different permissions (specifically what I need, all S3 permissions, etc)
  • Settings bucket policy
  • Clearing Chrome's cache (using Hard Reload) or by code before every try

I've tried everything and went over dozens of articles (1, 2) and browsing through questions here - but it's still not working. Not locally and not in production.


Solution

  • After endless hours of digging into this, I found the issue.
    The reason for the CORS error was that I didn't include the region in the initial AWS.config.update configuration setup.

    Once I added the region key, the CORS error was solved:

    const AWS = require('aws-sdk');
    
    AWS.config.update({
        accessKeyId: 'XXXXX',
        secretAccessKey: 'XXXXXX',
        region: 'us-west-2', // Must be the same as your bucket
    });
    
    const s3Client = new AWS.S3();
    

    It's really confusing and misleading that the error returned for not configuring the bucket region is CORS.