AWS API Gateway - CORS "access-control-allow-origin" - multiple entries

This has always been an annoyance with CORS if you want to enable several Origins.

The common workaround in other systems (e.g. express/nginx etc) is to:

  • inspect the Origin header sent by the browser
  • check it against a whitelist of origins
  • if it matches, return the incoming Origin as the Access-Control-Allow-Origin header, else return a placeholder (default origin)

This isn't possible using AWS-Gateway's autowired CORS support as uses a mock integration, it is however possible if you write your own code to process the OPTIONS request.

Below is example code written with lambda proxy integrations:

const allowedOrigins = [
    "http://example.com",
    "http://example.com:8080",
    "https://example.com",
    "https?://[a-z]*.?myapp.com",
    "http://localhost:[0-9]*"
];

exports.handler = (event, context) => {
    const origin = event.headers.Origin || event.headers.origin;
    var goodOrigin = false;

    if (origin) {
        allowedOrigins.forEach( allowedOrigin => {
            if (!goodOrigin && origin.match(allowedOrigin)) {
                goodOrigin = true;
            }
        });
    }

    context.succeed({
        headers: {
            "Access-Control-Allow-Headers": "Accept,Accept-Language,Content-Language,Content-Type,Authorization,x-correlation-id",
            "Access-Control-Expose-Headers": "x-my-header-out",
            "Access-Control-Allow-Methods": "DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT",
            "Access-Control-Allow-Origin": goodOrigin ? origin : allowedOrigins[0]
        },
        statusCode: 204
    });
};

Save this as a lambda function. To set this up in API-Gateway add an OPTIONS method and for the Integration Request choose Lambda Function with Use Lambda Proxy integration ticked.

Of course the downside to this is that you are paying for the lambda functions, and calling the lambda function will probably be an extra 50ms latency over the mock integration.


Why not use Velocity Template language mapping template to check from a list of allowed domains and set the origin header

$input.json("$")
#set($domains = ["https://www.example.com", "https://www.abcd.com"])
#set($origin = $input.params("origin"))
#if($domains.contains($origin))
#set($context.responseOverride.header.Access-Control-Allow-Origin="$origin")
#end