1

Background

I am currently building a web service using Serverless and AWS for the backend and Axios for calling the backend resources from a ReactJS frontend. Since the backend and frontend components are published under different domains, I need to use Cross-Origin-Resource-Sharing (CORS) to circumvent the Same-Origin-Policy that most browsers enforce by now.

The problem

Unfortunately, even though I have configured all of the Access-Control headers on the backend side (in AWS Api Gateway), I still get the error

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://example.com/internal/role. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

The data

Now, the issue I have is that when calling the OPTIONS call (not as a preflight but as a "standalone" call) on one of my resources with Postman, I receive the correct Access-Control headers. However, when issuing that same request with Axios, I do not seem to receive those headers which makes me think it might be an issue with Axios.

These are the Postman headers I receive when making the OPTIONS call:

 - Date: Fri, 26 Jun 2020 12:01:18 GMT
 - Content-Type: application/json
 - Content-Length: 0
 - Connection: keep-alive
 - x-amzn-RequestId: <some ID>
 - Access-Control-Allow-Origin: https://example-gui.com
 - Access-Control-Allow-Headers: Origin,Accept,Content-Type,X-Amz-Date,Authorization,X-Api-Key,x-requested-with
 - x-amz-apigw-id: <some ID>
 - Cache-Control: max-age=600, s-maxage=600, proxy-revalidate
 - Access-Control-Allow-Methods: OPTIONS,POST
 - Access-Control-Allow-Credentials: true

And these are the headers Axios tells me it receives when making the OPTIONS call:

 - cache-control: max-age=600, s-maxage=600, proxy-revalidate
 - content-length: 0
 - content-type: application/json

However, when using Firefox's dev tools, I can see that all headers are actually returned as seen in the Postman list. I don't know whether Axios just hides these fields or does not process them for some reason.

Unfortunately, I have no information about data returned by the actual POST call since it just throws the mentioned exception.

The Code

The Postman call is just a basic call to the respective URL with the OPTIONS method that only has one additional header (Authorization) so I'm not going to go into that any further.

The Axios call originates from the URL https://example-gui.com/#/ and is made like this:

const fullResponse = (response: AxiosResponse) => response;

const backendRequests = {
   ...
  options: (url: string, header: {}) =>
    axios.options(url, header).then(fullResponse),
  ...
};

const loginRequests = {
  getUserRole: (accesstoken: string) =>
    backendRequests.options(
      "https://example.com/internal/role",
      { Authorization: `Bearer ${accesstoken}` }
    ),
};

And then I print the result like this:

try {
  await agent.loginRequests
    .getUserRole(this.accessToken)
    .then((response) => {
      console.log(response); // <-- Printing the results
      <...>
    });
} catch (error) {
  console.log(error);
}

Which is where I got the list within the "The data" segment from.

The questions

Is it possible that this is a bug within the Axios framework, is it a configuration based issue where the Axios call has to be set up differently beforehand to receive all of the headers or does the problem lie somewhere else?

How can I manage to get through the Same-Origin-Policy with all of this information in mind?

Visparu
  • 11
  • 3
  • 1
    Have you used browser dev tools to see the OPTIONS call? Also, the domain is a very important detail. Instead of redacting, could you change the values but show the pattern of domain and ports involved? Ex. `example.com` – Davin Tryon Jun 26 '20 at 11:05
  • @DavinTryon I just checked it with the browser dev tools and Firefox seems to receive all headers returned by the backend. I have also edited the question to include your example.com advice. There are no non-standard ports used. – Visparu Jun 26 '20 at 11:24
  • What does your POST call perform? Basically you need to send the response back to your frontend within 29 seconds. So if you aren't responding before 29 secs you may receive a CORS error. – Sai Sreenivas Jun 27 '20 at 05:30
  • @SaiSreenivas The call returns in about a second, so that is unfortunately not the issue. Also, could you quote your source on this, please? As far as I know the only aspect of CORS that takes timing into account is when using the Access-Control-Max-Age header which only affects inter-call caching of the CORS headers. – Visparu Jun 28 '20 at 12:12
  • If you're not manually setting the headers on API gateway instead inserting them in the code itself causes the CORS error if response exceeds 29 seconds. btw you can view more about it [here](https://stackoverflow.com/questions/31973388/amazon-api-gateway-timeout) .Thanks – Sai Sreenivas Jun 28 '20 at 13:36
  • As you are saying the function replies within a second. I suggest you put the headers in the code itself rather than manually setting at the API gateway. – Sai Sreenivas Jun 28 '20 at 13:41
  • Ah I think I understand, you are referring to the overall execution time limit of the API Gateway. Thanks for clarifying. I just tried returning the CORS headers both as part of the integration response from API gateway in the preflight response and from the actual lambda code as well but unfortunately, that did not seem to help. The exception remains the same. In fact, The code is never executed in the first place, which is because the request is blocked by the browser before it reaches AWS, I suppose... – Visparu Jun 29 '20 at 18:46
  • I have the exact same issue as you do. Please tell me if you figured it out yet! – Simon Guldstrand Mar 16 '21 at 20:42

1 Answers1

-1

Have you checked if you are sending all the headers requested from backend service under Access-Control-Allow-Headers header from Axios. Maybe limit the number of headers to Access-Control-Allow-Headers: Accept,Content-Type and check if CORS is working.

You cannot use credentials if Access-Control-Allow-Origin uses *. You will have to specify the protocol + domain + port.

Access-Control-Allow-Origin wildcard subdomains, ports and protocols Cross Origin Resource Sharing with Credentials Use of * is too open and would defeat the use of credentials. So set http://domain:port as the allow origin header further.

Sovik
  • 59
  • 2
  • I have now checked the following cases: - Adding all headers sent with the Axios request to the CORS configuration in the backend - Allowing just those headers with CORS that are requested in the "Access-Control-Request-Headers" field of the preflight request Both attempts have unfortunately ended with the same exception. I have also restricted the * to https://example.com (I have to redact the actual domain but there are no unusual ports involved) Do I need to specifically add the 443 port when denoting the URL with https:// ? – Visparu Jun 26 '20 at 11:28
  • After some trial and error, I found out that it is actually possible to use the * in conjunction with Access-Control-Allow-Credentials == true, although for a private API that really doesn't make much sense, as you noted. – Visparu Jun 26 '20 at 16:24