Fix CORS "Response to preflight..." header not present with AWS API gateway and amplify
Asked Answered
Q

5

16

I've been struggling so long with the error below. I've tried so many tutorials and stackoverflow answers and none of the solutions fixes my problem.

Access to XMLHttpRequest at 'https://xxx' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

I'm using SAM serverless to create my api.

template.yaml:

Globals:
  Function:
    Timeout: 10
  Api:
    Cors:
      AllowMethods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
      AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
      AllowOrigin: "'*'"

My lambda function: Both my GET response and OPTIONS response has the following headers that is returned:

headers: {
  "Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'",
  "Access-Control-Allow-Origin": "'*'",
  "Access-Control-Allow-Methods": "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
}

My API get in my ReactJs application using amplify:

API.get(apiName, path, {
   headers: {
      "Access-Control-Allow-Origin": "*",
      // "Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,x-requested-with",
      // "Access-Control-Allow-Methods": "OPTIONS,POST,GET,PUT,DELETE",
      // 'Content-Type': 'application/json'
   }
})

I have tried every combination of Access-Control-Allow-Headers, Access-Control-Allow-Methods in my template.yaml, my lambda function and my reactJs project.

Here is what my result is when I call options in postman on my API endpoint. Thus I do get the correct headers back so per my understanding my API is allowing CORS. enter image description here

Quack answered 23/3, 2020 at 10:56 Comment(8)
What happens if you omit the "x-api-key" header in your options request?Greasewood
@JannesBotis In postman I get "Forbidden" but in my application I get the same error listed in my question (CORS error).Quack
Can you reply with a 200 status and the cors headers in this case also? Check #58547999 and https://mcmap.net/q/750170/-node-js-post-request-method-options-status-code-403-forbiddenGreasewood
@JannesBotis I'm not sure what you mean. When I have the "x-api-key" header I do receive a 200 OK status and the cors headers, but when I remove the "x-api-key" header I get a 403 Forbidden without the cors headers.Quack
Make the Options work also without "x-api-key"Greasewood
@JannesBotis I'm not sure how to do that. I tried to change my header to: "Access-Control-Allow-Headers": "'Content-Type'" but I still get the 403 Forbidden. I'm not sure if that is what you mean?Quack
Let us continue this discussion in chat.Quack
I am using AWS HTTP API Gateway, how to resolve it in AWS HTTP API Gateway?Carmen
Q
11

So after a very helpfull discussion with @Jannes Botis I found the solution.

In template.yaml I changed my values to:

Globals:
  Function:
    Timeout: 10
  Api:
    Cors:
      AllowMethods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
      AllowHeaders: "'Content-Type,X-Amz-Date,X-Amz-Security-Token,Authorization,X-Api-Key,X-Requested-With,Accept,Access-Control-Allow-Methods,Access-Control-Allow-Origin,Access-Control-Allow-Headers'"
      AllowOrigin: "'*'"

  MyAPIFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: myendpoint/
      Handler: app.lambdaHandler
      Runtime: nodejs12.x
      Events:
        GetMyData:
          Type: Api
          Properties:
            RestApiId: !Ref MyApi
            Path: /myendpoint
            Method: get
        Options:
          Type: Api
          Properties:
            RestApiId: !Ref MyApi
            Path: /myendpoint
            Method: options
            Auth:
              ApiKeyRequired: false

Note: You will get error "No 'xxx' header is present on the requested resource." where xxx is either Access-Control-Allow-Methods, Access-Control-Allow-Origin and Access-Control-Allow-Headers, thus you need to add them in your AllowHeaders. Also note that you have to add an Options resource with ApiKeyRequired: false.

Then your response from your options and get request should have the same headers:

headers: {
    "Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,X-Amz-Security-Token,Authorization,X-Api-Key,X-Requested-With,Accept,Access-Control-Allow-Methods,Access-Control-Allow-Origin,Access-Control-Allow-Headers",
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT",
    "X-Requested-With": "*"
}

Note: 'Accept' MUST BE PRESENT otherwise you will get "Response to preflight request doesn't pass access control check: It does not have HTTP ok status.".

Your preflight must be able to pass a 200 OK when you ommit the x-api-key in postman.

Quack answered 25/3, 2020 at 13:31 Comment(2)
CDK Users, you must have allowHeaders:['Content-Type', 'X-Amz-Date', 'X-Amz-Security-Token', 'Authorization', 'X-Api-Key', 'X-Requested-With', 'Accept', 'Access-Control-Allow-Methods', 'Access-Control-Allow-Origin', 'Access-Control-Allow-Headers'] in your corsPreflight parameter.Nahama
I am using AWS HTTP API Gateway, how to resolve it in AWS HTTP API Gateway?Carmen
C
4

I am including this response in case anyone is still pulling their hair out with this error. I spent a day trying to figure this out - reading everything I could about CORS and even migrating my code to the new AWS HttpAPI (which is probably a good thing anyway). Bottom line, I was fixated on the error message:

Access to fetch at 'https://api.example.com/user/list' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Which could point you in the wrong direction. My issue had nothing to do with the "Access-Control-Allow-Origin" header. In fact the answer to my issue was very simple, I was sending a JWT Token as part of the "Authorization" header, and I was not including a "Access-Control-Allow-Headers" entry in my response - duh! (but it would have been nice if the error message had been more accurate...)

If you are reading this you have probably already found many good sources of information on the web, but this site was very useful to me: www.test-cors.org

Cretin answered 12/11, 2020 at 14:43 Comment(4)
is this the same thing mentioned under 'Enabling CORS support for Lambda or HTTP proxy integrations' here? docs.aws.amazon.com/apigateway/latest/developerguide/…Appendicectomy
@Cretin You mention not including the "Access-Controll-Allow-Origin". From where in the code? The lambda? The request? According to these docs (docs.aws.amazon.com/apigateway/latest/developerguide/…) if you enable CORS on an httpAPI gateway, especially for the Preflight OPTIONS, "For a CORS request, API Gateway adds the configured CORS headers to the response from an integration." I'm seeing this behavior when hitting a POST endpoint using CURL ('Access-Controll-Allow-Origin' is being added to the header) but not for the Preflight OPTIONS request. Thoughts?Bedraggle
@Bedraggle in the request. Most clients (e.g. postman/Paw) will include these for you but if you are calling from your own code, I needed to include this in the request header "Access-Control-Allow-Headers"Cretin
life saver, thank you!Possession
M
3

This error can also occur if you are trying to access the wrong URL. D'oh. Before you descend into CORS madness, confirm that the request URL is correct and the resource is available.

In my case, I was trying to access the backend at a wrong Lightsail URL. Sending a POST request to this incorrect URL triggered the CORS error. With the correct URL everything worked fine.

Marlee answered 14/7, 2021 at 9:55 Comment(2)
I finally copy/pasted my url out of codepen and discovered that there was a hidden character that snuck into my URL 🤦‍♂️Concessive
Good comment, 90% of my cors problems are solved by checking the url and resource availability.Careaga
H
1

If Someone using serverless with nodejs and facing this issue of prelight with cors-policy, here is the simple solution ...

functions:
  externalHandler:
    handler: handler.handlerExport
    events:
      - http:
          path: handlerPath
          method: post
          cors:
            origin: '*' # <-- Specify allowed origin
            headers: # <-- Specify allowed headers
              - Content-Type
              - X-Amz-Date
              - Accept
              - Authorization
              - X-Api-Key
              - X-Amz-Security-Token
              - X-Amz-User-Agent
            allowCredentials: false

inside the handler file

if you are using express

...
const app = express();
app.use(function (req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Credentials", true);
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
  res.header(
    "Access-Control-Allow-Headers",
    "x-www-form-urlencoded, Origin, X-Requested-With, Content-Type, Accept, Authorization"
  );
  next();
});
...

or in general

  const response = {
    statusCode: 200,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Credentials': true,
    },
    body: JSON.stringify({
      product: product
    }),
  };

for more information refer serverless article

Hunchback answered 25/12, 2020 at 12:18 Comment(0)
M
0

For those using AWS CloudFront, and complementing the message from @PouncingPoodle, you can achieve the solution by editing your CloudFront Distribution and editing the Behaviour options Origin request policy, and Response headers policy.

Step 1: Open your CloudFlare Distribution, then Behaviour, select the option that applies, and click on Edit:

Edit Your CloudFront Behavior

Step 2: Scroll Down and Update Origin request policy. You have a few options there. In my case, as I am accessing EC2 from S3 Bucket, it was an easy choice, but if your situation is more complicated, you might need to create your policy.

Select the Origin Request Policy

Step 3: Update your Response headers policy. Also, we have a few options there. In my case, CORS-with-preflight-and-SecurityHeadersPolicy is what I needed.

Select the Response Headers Policy

Step 4: Save and wait for it to be deployed (it takes from 2 to 5 minutes).

Important: If you are running AWS CloudFront, EC2, and Docker and the problem still persists, review the processes from the start as sometimes the CORS error might appear in the browser, but your docker image threw a different exception.

To do that, run your docker image locally, execute the HTML call, and see if there is a problem. In my case, not only the AWS settings was wrong but my image was throwing an exception reporting a missing Python package.

If everything there goes fine, run the following curl command (Mac) and check if the header contains the Allowance Policies:

   curl -H "Origin:your_website_address.com" -v https://backend_address.com

This command can also test your CloudFront. What you want to expect is the following information: access-control-allow-origin, access-control-allow-methods and access-control-allow-credentials

enter image description here

Mariann answered 15/10, 2023 at 6:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.