14

I'm using Amplify, and have my API Gateway proxying to Lambda. I've enabled CORS on my /{proxy+} and deployed the API. In my Lambda function, I'm setting the appropriate header in my trivial function:

import json


def handler(event, context):
    print("received event:")
    print(event)
    return {
        "statusCode": 200,
        "headers": {
            "Access-Control-Allow-Credentials": True,
            "Access-Control-Allow-Headers": "Content-Type",
            "Access-Control-Allow-Methods": "OPTIONS,POST,GET",
            "Access-Control-Allow-Origin": "*",
        },
        "body": json.dumps(event),
    }

This Lambda function sits behind an API Gateway resource which is authenticated via Cognito.

When I invoke my API using Amplify:

let myInit = {
          headers: {
            Authorization: `Bearer ${(await Auth.currentSession())
              .getIdToken()
              .getJwtToken()}`
          }
        }; 

API.get("adminapi", "/admin", myInit) ...

I get the dreaded CORS header 'Access-Control-Allow-Origin' missing from my GET request:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/admin. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

I see it returned in the OPTIONS request:

enter image description here

I even tested in Postman to verify the headers are coming back:

enter image description here

What am I doing wrong here? It doesn't look like the call is getting past API Gateway. I wonder if it has to do with authentication. When I test from Postman using my IAM credentials it works fine, but from my web app using the bearer token it fails as above.

Mark Richman
  • 28,948
  • 25
  • 99
  • 159

8 Answers8

7

I've just struggled with something similar. The question here asks why the browser is returning a CORS errors when hitting API Gateway with Amplify despite CORS headers being configured correctly in the endpoint.

Aside from incorrect CORS header config, Amplify / API Gateway gives a CORS error if certain aspects of the request are incorrect. The ones I've comes across are:

  • The HTTP verb you are using does not exist against the endpoint
  • The endpoint you are using doesn't exist (e.g. a typo)
  • The Content-Type header is incorrect

The latter was causing me issues. It seems that Amplify.API.post and Amplify.API.put both send a Content-Type of application/x-www-form-urlencoded by default. My API was expecting application/json and the result was a CORS error.

Toomy
  • 318
  • 2
  • 10
0

I'd assume that you forgot to handle the OPTIONS verb that's used for the preflight request and return the header there.

You are sending an Authorization header, which is not in the list of allowed headers for "simple" requests, hence a preflighted request is done.

Furthermore, in order for credentials to get through, you have to ensure that the Access-Control-Allow-Credentials: true header is set as well.

It's not apparent from the code snippet what content type your request body is, but if it's anything other than application/x-www-form-urlencoded, multipart/form-data or text/plain (say, application/json), you also need to whitelist the Content-Type header using Access-Control-Allow-Headers: Content-Type.

CherryDT
  • 25,571
  • 5
  • 49
  • 74
  • `OPTIONS` is being handled (somewhere) because it returns `access-control-allow-origin: *`. I updated my function to include `"Access-Control-Allow-Credentials": True` in the response headers. Same situation. `Access-Control-Allow-Headers` is set in API Gateway by default as `'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'`. – Mark Richman Apr 14 '20 at 11:21
  • What happens if you put Fiddler in between? Check what actually goes over the line and how it differs from your tests. Maybe you are getting an error in your server (invalid authentication for example) which then won't return those headers (because it seems you only return them in the success case with status 200)? Maybe your authorization header is not sent because your library doesn't pass `withCredentials: true` to the XHR... – CherryDT Apr 14 '20 at 15:50
0

I was having the same issue. My pre-flight OPTIONS request had all of the correct headers:

access-control-allow-headers: Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent
access-control-allow-methods: DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT
access-control-allow-origin: *

So the browser started to accept requests after I added

access-control-allow-origin: *

To the response of the requests of the actual method I wanted to use (the non-preflight, eg: the GET, POST,etc method)

Alex Simons
  • 38
  • 1
  • 4
0

When using fetch() in js when I removed the Cognito Authentication from my API Gateway OPTIONS endpoints it worked. Chrome and Firefox don't send the Authorize headers to OPTIONS. Might be different with amplify though. Quoting: https://fetch.spec.whatwg.org/#http-responses ...

"For a CORS-preflight request, request’s credentials mode is always "same-origin", i.e., it excludes credentials, but for any subsequent CORS requests it might not be."
Mark
  • 136
  • 9
0

I just had this same problem pop up for me where I was working with Amplify and trying to secure the API Gateway to only be accessible to logged in users via Cognito.

The step that I had missed which you may have also missed is a bit of configuration within AWS API-Gateway. You need to go to the Gateway dashboard and create an 'Authorizer' which uses your Cognito User Pool. The token source is going to be whatever header label you are using for this (usually 'Authorization').

Creating new Authorizer

But you are not quite done. You then need to go to 'Resources' and change the Method Request to use your new Authorizer that you just created.

Using the new Authorizer with the resources

Hopefully after doing all this, you should be fine. If your user is logged in, and you add the Authorization header as you had:

let myInit = {
          headers: {
            Authorization: `Bearer ${(await Auth.currentSession())
              .getIdToken()
              .getJwtToken()}`
          }
        };

Then hopefully it all works out.

A video guide showing these steps can be found on here on Youtube, and starting around 10:50

Chuck Taylor
  • 188
  • 14
0

For anyone who is getting the same CORS error process as me: the preflight request was successful, and you configure everything with the '*' and the response headers allowed everything, but your actual request still got error. Please try to delete the AdminQueries api and its Lambda function and add everything again

Mink
  • 71
  • 7
0

If you are facing this error with AWS AMPLIFY then please check your Amplify configuration file.

  1. You might be missing identityPoolId if yes then add identityPoolId in your configuration.
  2. if identityPoolId is present then make sure that it is the correct one.

It is so because AWS AMPLIFY does not sign the request if idenitityPoolId is missing or incorrect.

I faced a similar issue and resolved my issue by this approach. Thanks

-3

In case it helps anyone: our team fixed this by adding scope aws.cognito.signin.user.admin to Cognito Auth provider settings.

Emre
  • 831
  • 11
  • 13