Configure CORS for an AWS S3 Bucket


Borislav Hadzhiev

Last updated: Sep 23, 2021


Photo from Unsplash

Configure CORS for an AWS S3 Bucket #

CORS is a mechanism that allows a server to use a combination of HTTP headers to indicate from which domains, other than its own, it receives requests.

By default servers only take requests made from applications hosted on the same domain.

All S3 buckets are hosted on the domain, which is different from where we host our client applications, so we have to set up CORS.

To configure an S3 bucket to allow cross-origin requests, you have to:

  1. Open your AWS S3 console and click on the bucket's name
  2. Click on the Permissions tab
  3. Scroll down to the Cross-origin resource sharing (CORS) section and click on the Edit button
  4. In the textarea, enter your JSON CORS configuration
[ { "AllowedHeaders": [ "*" ], "AllowedMethods": [ "GET", "HEAD", "PUT", "POST" ], "AllowedOrigins": [ "*" ], "MaxAgeSeconds": 3000 } ]

The CORS configuration consists of the following properties:

  • AllowedHeaders - which headers are allowed to be sent in a preflight (OPTIONS) request.

    In the example above we've used the * wildcard character to specify that all headers are allowed in a preflight request.

  • AllowedMethods - which HTTP methods the specified origins are allowed to perform on the S3 bucket.

    You might have to tweak this value, e.g. if your frontend only needs to make GET requests to the S3 bucket, you can remove the PUT and POST methods.

    Conversely, if you need to make DELETE requests to the S3 bucket, add the method.

  • AllowedOrigins - which origins (domains) are allowed to make requests to the S3 bucket.

    In our case we've set the value to a wildcard, meaning all domains. However, it's a best practice to only allow requests from known origins. If you own a domain this is what you would specify here.

    You can pass multiple origins in the array, however note that each origin can contain a maximum of 1 wildcard character. For example specifying an origin of https://*, would enable requests to your S3 bucket from all subdomains, e.g. - and

  • MaxAgeSeconds - this is an optional element. It defines the time in seconds that the browser caches an S3 response to a preflight OPTIONS request for the specified resource.

    If the response is cached, the browser doesn't have to send OPTIONS requests for the same resource over and over.

We can provide multiple rule objects in a CORS configuration, in fact up to 100 rules can be defined in a single CORS configuration.

Let's look at an example with 2 rules. The configuration allows PUT, POST and DELETE requests from a specific origin and GET requests from all origins.

[ { "AllowedHeaders": [ "*" ], "AllowedMethods": [ "POST", "PUT", "DELETE" ], "AllowedOrigins": [ "" ] }, { "AllowedHeaders": [ "*" ], "AllowedMethods": [ "GET", "HEAD" ], "AllowedOrigins": [ "*" ], "MaxAgeSeconds": 3000 } ]

In the CORS configuration above, we've specified that all origins can make GET requests to our S3 bucket.

However only the origin can perform POST, PUT and DELETE operations on the bucket.

It's a best practice to configure minimal permissions. Only include the AllowedMethods and AllowedOrigins that your application needs to function properly.

Further Reading #

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.