Access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response - amazon-web-services

I have prepared an Lambda function using Express(node.js) and enabled the Authorization with IAM as well.
The API is working in the Postman as per below link :
https://www.youtube.com/watch?v=KXyATZctkmQ&t=35s
As I'm fairly new with CORS policy and API concepts. I'm trying to access the sample using Ajax call.
So far I have prepared the Authorization Header as per documentation and few reference.
Git Repo Link : https://github.com/mudass1r/aws-iam-authorization.git
Reference Link for Signature Generation :
https://gist.github.com/davidkelley/c1274cffdc0d9d782d7e
I have Enabled the CORS from AWS API Gateway for my API as well.
PS : The API is Deployed using Serverless Framework.
Step 1 : The error I'm facing initial when I dont include any headers:
Step 2 : Later when I add headers:
$.ajax(Signer(credentials, {
url: <AWS API URL>,
type: 'GET',
dataType: 'json',
async: true,
crossDomain: true,
contentType: 'application/json',
headers: {
"Access-Control-Allow-Origin" : "*"
},
success: function(data) {
console.log(data);
}
}));
After which I get the following error:
In my previous experience with this error we only need to enable the CORS for the API which resolves this issue. But the same is not in this cases. Following is the structure of the API resource.
I have been stuck in this problem for few day and came across some CORS policy reference links as well.
https://fetch.spec.whatwg.org/#http-cors-protocol
Thanks everyone for your inputs and help.

Answer :
First of all the problem was not in header content. It was in the Authorization String which I was generating for AWS API Gateway authorization.
As pointed by #sideshowbarker. We don't need to add any headers in the ajax call.
The response header are enough to handle the API call.
app.use(cors())
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method,X-Access-Token,XKey,Authorization');
next();
});
Also I switched to Firefox for debugging the API call, where I found following errors.
Because I switched to Firefox, I could see the response from AWS from which I could further debug and fix the issue.
Issue in the CanonicalRequest function :
Before
'content-type;host;x-amz-date;'
After
'content-type;host;x-amz-date'
Thanks everyone for your inputs and help.
I have updated the git repo. Please refer the same.
https://github.com/mudass1r/aws-iam-authorization

Related

Call to API Gateway returning CORS error despite headers being set

I have an API Gateway (of type HTTP) that integrates with a Lambda function. I am trying to call that function from localhost as follows:
const jwt = getAuthToken();
const formBody = new FormData();
formBody.set('user', 'test');
const res = await fetch('https://example.execute-api.eu-west-1.amazonaws.com/default/GetShareValue', {
method: 'POST',
body: formBody,
headers: {
'Authorization': jwt
}
});
However, I get this error message:
Access to fetch at
'https://example.execute-api.eu-west-1.amazonaws.com/default/GetShareValue'
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. If an opaque response serves your needs, set the request's
mode to 'no-cors' to fetch the resource with CORS disabled.
I understand that incorrect CORS settings will prevent the browser from displaying what the Lambda function returns. However, my API Gateway has the CORS settings specified:
According to this thread, setting the headers in the Lambda function's response is important. I have set them to be identical. Here's my Lambda function:
exports.handler = async (event, context) => {
let body;
let statusCode = '200';
const headers = {
'Content-Type': 'application/json',
"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": "*",
"X-Requested-With": "*"
};
try {
body = "Success!!";
} catch (err) {
statusCode = '400';
body = err.message;
} finally {
body = JSON.stringify(body);
}
return {
statusCode,
body,
headers,
};
};
I can call this endpoint in Postman - which doesn't care about CORS - so I know it's working. I am starting to think that this is a bug within AWS itself.
Answering my own question for the benefit of #peter n.
In the end I abandoned the HTTP API Gateway. I believe there is a bug in AWS as the exact same Lambda function worked when I triggered it via a REST API. Here's what I did.
Create a new API Gateway
Select the type of the API Gateway as REST API. I previously had selected HTTP. The REST API gives us more control; the HTTP API is simple (and 70% cheaper)
On the Resources page, click Actions > Create Resource
Create the resource; if you see any checkbox mentioning CORS then check it. I can't remember if this occurs at this stage.
Then click Actions > Create method
Select any method (like POST, GET etc.) other than "Any". This is important - if you select "Any" there are further issues with CORS. Why? Who knows, AWS is a user-unfriendly platform.
Once you've configured the method and got it firing at your Lambda function (or whatever you're integrating with) test it with something like Postman, which doesn't care about CORS.
Finally, to get CORS working click Actions > Enable CORS
I entered the following settings:
Methods: POST
Access-Control-Allow-Methods: OPTIONS, POST
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: '*'
Then click "Enable CORS and replace existing CORS headers".
You're not done yet. This still won't solve the issue if you're targetting a Lambda function. You need to add the CORS headers to the actual response of your Lambda.
Here's the full code for my Lambda:
exports.handler = async (event, context) => {
let body = JSON.stringify('Success!');
let statusCode = '200';
const headers = {
'Content-Type': 'application/json',
"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": "*",
"X-Requested-With": "*"
};
return {
statusCode,
body,
headers,
};
};
I am not sure if it matters that the CORS settings you return in the Lambda are the same CORS settings that you applied in the AWS Console.
This is a real headache and, unless I am doing something wrong, AWS have implemented this very badly.
Update: After having further issues with this I thought I'd update my answer to state that the request you make also seems to impact on CORS. I was making changes to my API and the CORS error started happening again; eventually, the only solution was to remove some of the headers in the request I was sending to AWS.
This caused CORS errors:
const res = await fetch('https://123.execute-api.eu-west-1.amazonaws.com/test', {
method: 'POST',
headers: {
'Authorization': jwt,
"Access-Control-Allow-Origin": "*" // This had to be removed to fix the CORS error
}
});
As you can see, I was specifying Access-Control-Allow-Origin in the outbound request to my API. This was always there and never caused issues, but seemingly now I can comment and uncomment that line in the request and get/not-get the CORS error.
Update #2: A further update to save anyone who may be banging their head against the wall for this.. after adding new sources and methods to an existing API Gateway, be sure to click Actions > Deploy API so your changes are actually live.
AWS really need to clean up the whole UI for API Gateway and Lambda. It is not clear at all that you have unpublished changes or that publishing is even required; the UI makes it seem like any changes are instantly live.
The main problem is in the answer provided by the Options method. For some reason, the mock response, at least in my case, does not work correctly, so I have linked it with a lambda whose sole purpose is to respond with a 200 code and returning all the necessary headers.
Therefore, what you have to do is, inside the options method of the resource with CORS enabled, change the integration request to Lambda.
Once this is done, we must develop the lambda so that it returns a 200 as a response and accepts all the necessary headers:
{
'statusCode': 200,
'headers': {
'Content-Type': 'application/json',
"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": "*",
"X-Requested-With": "*"
},
'body': json.dumps({})
}

API Gateway HTTP API CORS

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.

.NET Core 3.1 CORS not working on Ember (3.12) web UI

I am migrating a .NET Core Web API from 2.2 to 3.1. I have followed the Microsoft migration instructions and placed the call to the CORS middleware between UseRouting and UseEnpoints. However, I am still getting CORS errors.
In the ConfigureServices method, I have:
services.AddCors();
In the Configure method, I have:
app.UseRouting();
app.UseCors(options => options
.AllowAnyOrigin()
.AllowAnyHeader().AllowAnyMethod()
);
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
The console error in the web browser is:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://localhost:5000/users/login. (Reason:
CORS header ‘Access-Control-Allow-Origin’ missing).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://localhost:5000/users/login. (Reason:
CORS request did not succeed).
Diagnostics:
I tried following Microsoft's documentation Enable Cross-Origin Requests (CORS) in ASP.NET Core, but it uses outdated references, such as; UseMvc and IHostingEnvironment.
I tried creating a brand new Web API and Ember Web-UI, but that did not work either. You can find a simple example getting-started-with-ember-js-and-net-core-3
Any idea what is causing the problem?
The ideal bounty reward will go to the answer that works. Preferably, a working bare-bones project will be posted on Git.
Note: I am allowing any origin right now just so I can get it to work. Ultimately, this will need to work with a Web-UI that is on http://localhost:4200
Update
The status code received is HTTP 405 - method not allowed. The method in question is an OPTIONS method.
The .NET Core 2.2 to 3.0 migration document is incorrect. The call to UseCors(); needs to be placed before the UseRouting() function. I went ahead and added it before the UseHttpsRedirection() as I saw that in an implementation on another site.
https://learn.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio#migrate-startupconfigure
In ConfigureServices
services.AddCors(options =>
{
options.AddPolicy("CorsApiPolicy",
builder =>
{
builder.WithOrigins("http://localhost:4200")
.WithHeaders(new[] { "authorization", "content-type", "accept" })
.WithMethods(new[] { "GET", "POST", "PUT", "DELETE", "OPTIONS" })
;
});
});
In Configure
app.UseCors("CorsApiPolicy");
//app.UseHttpsRedirection();
app.UseJsonApi();
app.UseRouting();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});

CORS access error for PUT method, api on aws hosted on elastic beanstalk

I've deployed an api on AWS API Gateway using http custom integration
I've enabled CORS as seen below:
(source: upload.cat)
For both GET and PUT methods, I am getting the following error:
"url from origin [my origin] has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource"
Code:
fetch(url, {
method: 'POST',
mode: "cors",
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token' //copied from screenshot above
},
body: JSON.stringify(data)
})
.then(response => console.log('Success:', response))
.catch(error => console.error('Error:', error));
}
Access-Control-Allow-Headers are set in the server, you should remove it from your code. It won't make any difference if you put it in your request.
Is your API Gateway method protected by Lambda Authorizer or configured to use an API Key? If so, request might be rejected by one of them and response won't include Access-Control-Allow-Origin header so browser's preflight check will be failed.
You also need to check what response is being returned by API method integration. In case of Proxy Lambda, response should include Access-Control-Allow-Origin header.
Take a look at integration response documentation.

request api gateway cors error

I created a AWS API GATEWAY,and following aws doc totur step create api and Enable CROS and Deploy !
Enable CORS
✔ Create OPTIONS method
✔ Add 200 Method Response with Empty Response Model to OPTIONS method
✔ Add Mock Integration to OPTIONS method
✔ Add 200 Integration Response to OPTIONS method
✔ Add Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin Method Response Headers to OPTIONS method
✔ Add Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin Integration Response Header Mappings to OPTIONS method
✔ Add Access-Control-Allow-Origin Method Response Header to POST method
✔ Add Access-Control-Allow-Origin Integration Response Header Mapping to POST method
Your resource has been configured for CORS. If you see any errors in the resulting output above please check the error message and if necessary attempt to execute the failed step manually via the Method Editor.
Get an error message when I used this api:
XMLHttpRequest cannot load https://xxxxxxx.amazonaws.com/xxxx/xxxx. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:7076' is therefore not allowed access. The response had HTTP status code 400.
What step should I've been done?
Finally i found what happen in my error!
The payload sent from AJAX to API Gateway is not in JSON format, but LAMBDA's input supports only JSON-formatted data, which causes LAMBDA to not process the input normally. This in turn led to a mistake in LAMBDA's operation.
When this happens, API GATEWAY will not receive a normal response, so it will not return 'Access-Control-Allow-Origin' to the client (AJAX), so there will be no HTTP The wrong head.
This problem is resolved after i've processed the payload using the JSON.stringify () function.
I've got similar problems recently and assuming you've deployed your API:
and assuming again you are using some js client like jQuery, you may take in mind some POST/GET parameters:
HTTP GET Request
$.ajax({
crossDomain : true,
contentType : 'application/json',
method : "GET",
url : YOUR_API_GATEWAY_URL,
dataType : "json"
}).done(...)
HTTP POST Request
$.ajax({
data : JSON.stringify({
param1 : val1,
param2 : val2,
...
}),
crossDomain : true,
contentType : 'application/json',
method : "POST",
url : YOUR_API_GATEWAY_URL,
dataType : "json"
}).done(...)