I have a AWS Lambda instance that connects to a defined AWS API Gateway. If I enable CORS and give the access-control-allow-origin
a definition of http:/
I did something like this:
const handler: APIGatewayProxyHandler = async (event) => {
const origin = event?.headers?.Origin || event?.headers?.origin;
const allowedOrigins = ['https://example.com'];
const headers = {
'Access-Control-Allow-Origin': allowedOrigins.includes(origin)
? origin
: allowedOrigins[0],
};
return {
headers,
body: JSON.stringify({
myResponse: 'data',
}),
statusCode: 200,
};
};
Can then test via chrome dev tools by going to your client domain and running a fetch in the console:
fetch('https://exampleLambda.com/v1/example', {
method: 'get',
mode: 'cors'
headers: new Headers({
'Authorization': 'Bearer 12345,
}),
})
.then(result => result.json())
.then(console.log)
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:
Origin
header sent by the browserOrigin
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
Unfortunately this is not possible today. The CORS spec does not allow for partial wild cards and currently API Gateway only allows a single static value for the header.
You may be able to overload your OPTIONS method to return this value dynamically based on the incoming host header.