For some reasom this error appears from nowhere:
has been blocked by CORS policy: Request header field x-company-id is not allowed by Access-Control-Allow-Headers in preflight response.
Here is my serverless.yml lambda function:
healthPlan:
handler: src/handlers/health-plan.healthPlanHandler
events:
- http:
path: /health-plan
method: get
cors:
origin: ${self:custom.allowed-origin}
allowCredentials: ${self:custom.allow-credentials}
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- X-Amz-User-Agent
- X-Company-Id
- x-company-id
authorizer:
authorizerId: ${cf:auth-service-${self:provider.stage}.ApiAuthorizer}
type: TOKEN
I'm new to serverless. Could someone give me advice or the answer for current situation? Where should I look?
Thanks a lot for help!
Firstly, are you sure you need x-company-id? I see you have also X-Company-Id, which I'm guessing might be the actual header AWS expects?
Likely x-company-id is being treated as a custom header. I had this same CORS issue with Serverless and AWS when trying to pass actual custom headers to my API.
My issue was resolved by adding a resources section to serverless.yml to include CORS headers in API Gateway-level error responses and including CORS headers in the normal responses of my lambda handler.
The instructions for performing these 2 steps I found here:
https://dev.to/leventov/enable-cors-with-custom-headers-for-an-aws-lambda-function-behind-api-gateway-in-serverless-framework-3702
Note that, instead of including each header explicitly in the access-control-allow-headers field, you can also just whitelist all headers with * if this is not a security concern.
I am using the new API Gateway HTTP which during the configuration enables you to add CORS. So I have set the Access-Control-Allow-Origin Header with the setting *.
However when I make a request using Postman I do not see that header and this i causing my VueJS Axios request to fail.
I previously used a Lambda Proxy Integration and did the following in my Lambda
"headers": {
"Access-Control-Allow-Origin": "*"
}
However the new HTTP API just does not seem to implement CORS. Maybe I am missing something simple.
--EDITS--
So I have continue to find an answer and came across a blog post from the guys at Serverless who set the following
It’ll ensure following headers:
Access-Control-Allow-Origin: *
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:
OPTIONS, and all the methods defined in your routes (GET, POST, etc.)
I have tried these and redeployed and still only get the standard headers
Thanks
For anyone using HTTP API and the proxy route ANY /{proxy+}
You will need to explicitly define your route methods in order for CORS to work.
Wish this was more explicit in the AWS Docs for Configuring CORS for an HTTP API
Was on a 2 hour call with AWS Support and they looped in one of their senior HTTP API developers, who made this recommendation.
Hopefully this post can save some people some time and effort.
If you have a JWT authorizer and your route accepts ANY requests, your authorizer will reject the OPTIONS request as it doesn't contain an Authorization/Bearer token. To resolve this issue, you need to explicitly point your route to the HTTP request/method you need. E.g. POST
In that case, your authorizer will ignore the OPTIONS request without a JWT and proceed with the required request.
(This is answer just for AWS HTTP api gateway/AWS api gateway v2).
I have met the same problem and I asked the AWS support finally. The tricky thing is actually CORS had been already working after we configured it, but I just didn't get how to test it (it's different from AWS REST API ), when test we need to specify the Origin(should be same with your setting:Access-Control-Allow-Origin in cors, like: http://example.com) and the Request method.
For example:
curl -v -X GET https://www.xxx.yy/foo/bar/ -H 'Origin:http://example.com' -H 'Access-Control-Request-Method: GET'
Then it would return the CORS header you had set in response header:
access-control-allow-origin, access-control-allow-methods, access-control-allow-headers, etc.
I just hope this can save time for who met the similar problem.
By the way, I hope AWS can update this test way to offical Document(it's not very useful, but most of people must be saw it before find real answer):
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html
My issue was that I was sending this headers :
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Credentials
From the web request and it was messing with the Access-Control-Allow-Headers. I removed them and it's fine now.
To debug CORS issue with AWS HTTP API, try to put a * in each field of the CORS configuration in the AWS Console and reconfigure each field one by one.
So even though i was getting cors headers in my post call, browsers were still failing,,
My solution was
explicitly create an OPTIONS route with same path {proxy+}
attach same lambda integration to it
have the lambda function return early with success headers
if (method === 'OPTIONS') {
return {
headers: { 'Access-Control-Allow-Origin': '*' },
statusCode: 200
}
}
tldr; x-api-key
It took some searching and trial and error, but I got CORS working for API Gateway HTTP API. For the very basic GET request from a jQuery ajax call here is what I had to do:
AWS Console CORS settings, needed Access-Control-Allow-Headers: x-api-key
Then, in my ajax call, I had to send a dummy x-api-key (I did not configure one, so not sure why it wants it.):
$.ajax ({
url: 'https://xxxxxxx.execute-api.us-east-1.amazonaws.com/prod/stuff/',
crossDomain: true,
method: 'GET',
headers: {
"accept": "application/json",
"X-Api-Key":"blablablalla"
},
success:function(data){
doStuff(data);
},
error: function(){
alert('error');
}
})
You may need additional configuration depending on your situation, but the x-api-key was what I narrowed down as the oddest undocumented requirement.
I have a Lambda function and when I call it from my React app I get the following 2 errors:
POST https://x7429ccke5.execute-api.eu-west-1.amazonaws.com/prod/sites 500
and
Uncaught (in promise) Error: Request failed with status code 500
at createError (createError.js:17)
at settle (settle.js:19)
at XMLHttpRequest.handleLoad (xhr.js:78)
I do not have a log in system on my website yet so I want to call the api without needed permission so on my serverless.yml, I have it as
functions:
# Defines an HTTP API endpoint that calls the main function in create.js
# - path: url path is /notes
# - method: POST request
# - cors: enabled CORS (Cross-Origin Resource Sharing) for browser cross
# domain api call
# - authorizer: authenticate using the AWS IAM role
createSite:
handler: CreateSite.main
events:
- http:
path: sites
method: post
cors: true
arn: "arn:aws:execute-api:eu-west-1:106845550704:x7429ccke5/*/POST/sites"
I am suspecting the problem is with API Gateway's integration with lambda. It's your API Gateway that is throwing the 500 error. Please check if your API Gateway is staged or not. If it's staged then check for this:
https://docs.aws.amazon.com/apigateway/latest/developerguide/amazon-api-gateway-using-stage-variables.html#call-api-http-backend-via-stage-variable
Let me know if it still doesn't work.
I'm using AWS Serverless for building a small site with around 15 Lambda functions.
My Cloudformation stack is completely built using SAM.
I'm NOT using Lambda proxy integration.
The Api section in the SAM yaml template config looks like this:
AppApi:
Type: AWS::Serverless::Api
Properties:
Cors:
AllowMethods: "'*'"
AllowHeaders: "'Content-Type'"
AllowOrigin: "'*'"
...........More Stuff..........
When I deploy this SAM yaml template, I see that my ApiGateway created the OPTIONS verb for all methods and when I shoot a request with the OPTIONS verb, I do see the CORS headers correctly.
The problem is that the other verbs (e.g. POST) don't add those headers to their response as the OPTIONS request did and when I run my api from the browser I get the cross origin policy error in my console.
So my current workaround was to add the CORS header using integrated responses to specific status codes, but I cannot and dont want to handle that for 15 methods and I want to support all response status codes (e.g. 4xx\5xx etc.).
My questions:
Am I doing anything wrong here or is this a SAM bug?
If this is a bug, is there any workaround other from adding the headers using integrated responses (or from my code)?
Is there a way I can add headers "globally" from an Api Gateway? Or support some kind of global integrated responses?
If you are using Lambda with Proxy Integrations, you need to specify the CORS Origin in your HTTP response.
For Lambda or HTTP proxy integrations, you can still set up the
required OPTIONS response headers in API Gateway. However, you must
rely on the back end to return the Access-Control-Allow-Origin headers
because the integration response is disabled for the proxy
integration.
https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html
All responses from Lambda need to have these headers and status code, but you could extract that to a shared library to reduce code duplication. Errors handled by API-G will have the headers added automatically.
You probably already have this, but the NodeJS pattern is like this:
var response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin" : "*"
},
body: JSON.stringify({
someReturnData
})
};
callback(null, response);
If you really don't want to do this then you can turn off Lambda-Proxy Integration, but that means that all request response payloads need to be handled in API-G instead of Lambda. IMO this provides much less flexibility and more configuration required to achieve the same results.
Here is an interesting comparison of the two approaches.
Is there a way to map all parameters,headers and body to the other http endpoint? does it require a special template?
This is what I've got so far:
functions:
myfunction:
handler: lambda.myfunction # dummy hanlder
events:
- http:
path: resource/{resourceId}/other
method: get
integration: HTTP
request:
uri: http://url/resource/{resourceId}/other
parameters:
'method.request.path.resourceId': true
'method.request.header.my-header': true
response:
statusCodes:
200:
pattern: ''
Whenever i create directly in the console the the passthrough option is enabled by default and it maps the resourceId correctly.
I tried to look into the documentation but seems that there's almost no documentation on the http integration, unless i'm missing something.
Is there a way to map all parameters,headers and body to the other http endpoint? does it require a special template?
Yes, use HTTP_PROXY integration type. In the console this is a checkbox in the Integration Request page.
I was able to find a workaround to have this working, seems more a workaround than the correct solution.
I had to set the Integration.RequestParameters in the resources of the serverless.yml to achieve this.
resources:
Resources:
ApiGatewayMethodV1ResourceResourceidVarOtherGet:
Properties:
RequestParameters:
method.request.path.resourceId: true
method.request.header.my-header: true
Integration:
RequestParameters:
integration.request.path.resourceId: method.request.path.resourceId
integration.request.header.my-header: method.request.header.my-header