DEV Community

Cover image for How to Solve CORS Issues with Express in Amazon S3 by AWS
Federico Moretti
Federico Moretti

Posted on

How to Solve CORS Issues with Express in Amazon S3 by AWS

Today, I had a headache trying to solve some problems on S3: I was unable to make HTTP GET calls to a domain outside of AWS. Or, to be even more precise, I couldn’t get two different domains, both managed by Amazon, to communicate with each other. But I found a solution for this.


Cross-Origin Resource Sharing (CORS) is one of the most common problems with HTTP calls. We can’t do without it, since normally we wouldn’t share information between different domains, but sometimes we have to: this time I needed to get a message from a third-party web service.

I have a lambda function built with Express which acts as a proxy that filter HTTP calls to an external service (it’s hosted on Azure, but it doesn’t matter here) based on some parameters, and a web page where I want to show the retrieved information. This latter is hosted on a public-access S3 bucket.

There are two different types of problems here: one at the back-end level and one at the front-end level. Starting from the first, I had to add CORS capabilities to the API by installing a middleware. I thought it would have solved all my problems, but it didn’t.

npm i --save cors
Enter fullscreen mode Exit fullscreen mode

If you use TypeScript, you can add @types/cors to development dependencies, because @types/express are not enough. Usually, I would have configured all the routes to implement it, but I found a better way of enabling CORS capabilities by modifying only the path I need.

import cors from 'cors';

[]

app.get('/path', cors({
  origins: true,
  credentials: true
}), (req, res) => { [] });
Enter fullscreen mode Exit fullscreen mode

This way, you can avoid using app.use(cors()) and extend the CORS to all your routes, if you don’t need to. Let’s say that the back-end issue is now solved, but you will still get an error on the front-end side. I’m using fetch() there, but you can easily adapt my solution to other libraries.

await fetch('https://domain.ext/path', {
  method: 'get',
  mode: 'cors',
  credentials: 'include'
}); 
Enter fullscreen mode Exit fullscreen mode

Above, an example about how to handle the HTTP call. Unfortunately, due to Amazon default settings on buckets, this is still not enough to make things work. You must fix S3 policy to enable CORS for your web page. I suggest to customize the following JSON structure to only allow resources you trust.

"AllowedOrigins": [
  "*"
]

"AllowedMethods":[
  "GET",
  "HEAD"
]

"AllowedHeaders":  [
  "*"
]
Enter fullscreen mode Exit fullscreen mode

The configuration I proposed above is very permissive: maybe, too much permissive. Don’t use it as-is, if you don’t know what are you doing, because it basically allows anything. Notice the HEAD method, since I didn’t succeed to make a CORS request without it.

I didn’t need to expose custom headers, then I simply left the ExposeHeaders array empty. Once the changes have been propagated, I finally see it working: I was able to make a GET request to the lambda from the web page and getting the results. It wasn’t that hard to achieve, but I didn’t know about these properties.

I thought that having a public-access bucket on S3 was enough to enable CORS requests, but I was wrong, and to be honest I feel safer this way. I can selectively enable origins, methods, and headers to allow only specific requests, instead of allowing anything to anyone.


What a day! I learnt something new about Amazon S3, and solved an issue that could have affected other projects I tried to build in the past. I hope this solution can help you with yours. Check both side of your environment twice to be sure that CORS has been enabled successfully.

Top comments (0)