AWS APIGateway CORS for Lambda Proxy does not apply - javascript

I have set up a APIGateway resource with a POST Lambda Proxy method, and an OPTIONS method for CORS headers.
The OPTIONS method returns these headers:
$ curl -i -X OPTIONS https://xxxxxxxxx.execute-api.eu-central-1.amazonaws.com/dev/endpoint1
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 0
Connection: keep-alive
Date: Sat, 18 Feb 2017 17:07:17 GMT
x-amzn-RequestId: xxxx
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token
Access-Control-Allow-Methods: POST,OPTIONS
X-Cache: Miss from cloudfront
Via: 1.1 xxxx.cloudfront.net (CloudFront)
X-Amz-Cf-Id: xxxx==
Yet when I call the POST endpoint with the generated Javascript SDK, the Chrome browser console shows this error:
XMLHttpRequest cannot load https://xxxx.execute-api.eu-central-1.amazonaws.com/dev/endpoint1.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:8080' is therefore not allowed access.
as well as Firefox:
Cross-Origin Request Blocked:
The Same Origin Policy disallows reading the remote resource at https://xxxx.execute-api.eu-central-1.amazonaws.com/dev/endpoint1.
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
Why is my CORS header not taken into account? Are additional changes of the POST method settings required?

It seems to be required to add the headers manually in the lambda function.
In the case of NodeJS the script would look like this:
context.succeed({
"statusCode": 200,
"headers": {
"X-Requested-With": '*',
"Access-Control-Allow-Headers": 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,x-requested-with',
"Access-Control-Allow-Origin": '*',
"Access-Control-Allow-Methods": 'POST,GET,OPTIONS'
},
"body": JSON.stringify(response)
})

A better approach would be to use the API Gateway to enrich the payload from your lambda with CORS related headers as described here: https://kennbrodhagen.net/2015/12/02/how-to-access-http-headers-using-aws-api-gateway-and-lambda/
This is a much more scalable and less error prone approach.

Please check below points.
Did you deploy your updated API?
Did you create OPTIONS method for your API resource?
Did you add response headers for Method Response of OPTIONS method like below?
Access-Control-Allow-Headers
Access-Control-Allow-Methods
Access-Control-Allow-Origin
Did you perform 'Enable CORS' action on your API Resource?
After complete to check above, please check the Method Request of GET/POST Method of your API Resource. Perhaps, Access-Control-Allow-Origin HTTP header was added automatically by API Gateway.
Thanks,
Daniel

Related

Angular 2: Simple Get request to external API blocked for CORS but got 200 in network surveillance

I am just learning Anuglar 2 by creating a small project. This project is dependent on an external API that does not allow CORS. Because I only need to make GET requests on the API I am comfortable making the simple type of GETs that avoids the CORS restriction.
When I execute my code then I see in my Firefox developer tools network surveillance that the call goes through as a GET (Not an "Option" as would be the case if I were truly blocked by CORS) and I can see a valid response with HTTP status 200.
The problem is that my angular code still fails with the "Standard" CORS error and dumps an object.
I Tried reading through the dumped object in the hopes of understanding the error better, but so far no luck.
I did try googling this, but the majority of cases are not satisfied with the simple requests that gets around CORS so I were not able to find some help on my own.
This does not seem to be a Firefox problem because I can see the succeeded GET request, so I believe it is a Angular 2 problem. Can you help me get this working?
Here is my code sample including the URL to the external API:
testingObervable(): void {
this._http
.get(`http://oda.ft.dk/api/Sag?$inlinecount=allpages&$filter=typeid%20eq%203`,
{ headers: this.getHeaders() })
.subscribe(data => {
console.log(data);
});
}
private getHeaders() {
let headers = new Headers();
headers.append('Accept', '*/*');
return headers;
}
Here is the "Standard" CORS Error I get in Firefox:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://oda.ft.dk/api/Sag?$inlinecount=allpages&$filter=typeid%20eq%203. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
Here is the response header from the External API:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.5
DataServiceVersion: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 01 Jan 2018 17:13:14 GMT
Content-Length: 34771
This is the collapsed version of the dumped object after the CORS error, I do not know if it is relevant, but it is sure not that informative to me.
ERROR Object { _body: error, status: 0, ok: false, statusText: "", headers: {…}, type: 3, url: null } core.js:1427
Some ressource on CORS: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
This is not an issue with your code or with Angular. It's how CORS is supposed to work.
Because I only need to make GET requests on the API I am comfortable making the simple type of GETs that avoids the CORS restriction.
A request of this 'simple' type does not avoid the CORS restriction, but sending a preflight is not required for those requests. The response should still include CORS headers for the request to be allowed by the browser.
The resource on CORS that you link to points this out at the functional overview part (emphasis mine):
The Cross-Origin Resource Sharing standard works by adding new HTTP headers that allow servers to describe the set of origins that are permitted to read that information using a web browser. Additionally, for HTTP request methods that can cause side-effects on server's data (...), the specification mandates that browsers "preflight" the request (...)
In short, while CORS applies to all cross-origin HTTP requests, the preflight is only sent for certain kinds of HTTP requests.

No 'Access-Control-Allow-Origin' header is present in Rails API backend

I have a jsonapi-resources backend api in Rails. I am able to request data using curl as well as in Python.
When I try using jQuery for the request I get the following error in the browser:
XMLHttpRequest cannot load
https://shop-api-3.herokuapp.com/customers?filter%5Bshop_token%5D=9e3c9769b752436ddbd27597cf946a36.
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'null' is therefore not allowed access. The response
had HTTP status code 404.
So I added this to config/environments/production.rb:
config.action_dispatch.default_headers = {
'Access-Control-Allow-Headers' => 'Origin, X-Requested-With, Content-Type, Accept, Authorization',
'Access-Control-Allow-Origin' => '*',
'Access-Control-Request-Method' => '*',
'X-Frame-Options' => 'ALLOWALL'
}
However, I'm still getting the same error. What am I missing?
FWIW, this is my curl command:
curl -i -H "Accept: application/vnd.api+json" "https://app.herokuapp.com/retentions?filter%5Bshop_token%
5D=ABC123"
Using Rails 4
I had this same issue a month ago and after reading a lot of blogposts, I solved it by...
So it looks like you are requesting an api token, on another server using jquery(from the browser) rather than doing this, request it from ur server and ounce you get it pass it to the client and then you can do whatever you want, this should do the trick.
My understanding of this CORS is you cant do browser to server, you have to do it from server(your domain) to server(the api that you are accessing).
Hope this helps!

CORS header has information but Angular js $http.get does not work

I am using angular js to consume a rest service . The rest api does return required headers but I get
Response for preflight has invalid HTTP status code 401
and in mozilla I get
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://testurl.com:8081/v1/users. (Reason: CORS preflight channel did not succeed).
error
API header returns gives
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS, DELETE
Access-Control-Allow-Headers: x-requested-with, Authorization
Access-Control-Expose-Headers: x-requested-with
Access-Control-Max-Age: 3600
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
X-Application-Context: application:8081
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 05 Jan 2016 14:57:20 GMT
Below is http request
$http({
method: 'post',
url: 'http://testurl.com/v1/users',
data : data
}).then(function successCallback(response) {
object.sucess=true;
object.massage=response;
console.log('success');
}, function errorCallback(response) {
object.sucess=true;
object.massage=response;
});
Am I doing something wrong or the problem is in header .
As I read your problem i have also faced this problems and this problem can be resolved from server side as well from client side also by creating proxy server. In server side you need to allow the ip of your system.
Usually their are 3 solutions as i know.
1).
Example: As What i do while creating web service in NodeJs(API):
res.setHeader('Access-Control-Allow-Origin', 'http://hostname.com');
// Request methods you wish to allow
// You can write * also for allowing to access that url from all systems which is not done usually for security purposes
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
Then you can run get as well as post request too.
2). You can also create proxy server to handle that post and put reuests so that communication to that api will be constant
3). You can install CORS plugin in your chrome browser and enable it and you can query to the server side.
https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?utm_source=chrome-ntp-icon
I found the solution . It was missing preflight OPTIONS. I had to add those in my back end . Now it works fine .
You have put Authorization as an allowed header. This is incorrect, instead you need to add Access-Control-Allow-Credentials which will allow this header.
This separate setting controls the browser sending cookies as well as Authorization header

Is the Access-Control-Allow-Origin CORS header required when doing a preflight request?

We are seeing the well-known CORS error on our site:
XMLHttpRequest cannot load https://my-site.com/api. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://my-other-site.com' is therefore not allowed access.
The thing is, the Access-Control-Allow-Origin is set correctly on the preflight request...
OPTIONS https://my-site.com/api HTTP/1.1
Host: my-site.com
Access-Control-Request-Method: POST
Origin: https://my-other-site.com
Access-Control-Request-Headers: my-custom-header, accept, content-type
Accept: */*
Referer: https://my-other-site.com/
...other stuff...
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://my-other-site.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: my-custom-header, accept, content-type
Access-Control-Expose-Headers: my-custom-header
...other stuff...
...however, it's not set on the subsequent request.
POST https://my-site.com/api HTTP/1.1
Host: my-site.com
Accept: */*
My-Custom-Header: abcd123
Origin: https://my-other-site.com
Referer: https://my-other-site.com/
...other stuff...
HTTP/1.1 200 OK
My-Custom-Header: abcd123
...other stuff...
I don't understand the problem. According to everything I've read online, if we use a preflight request, we shouldn't need to add CORS headers for the actual request. However, that's clearly not the case.
All of the examples here and here include an Access-Control-Allow-Origin header in the actual response, but don't include any of the other "required" CORS headers. When we add that one header to our actual response, the error goes away.
So my question is, is the Access-Control-Allow-Origin header actually required in both requests? Where is that stated? And why is that true?
Yes, it appears both responses should include the necessary CORS headers.
In both the Simple Cross-Origin Request and the Cross-Origin Request with Preflight, the "actual request" follows the same behavior, checking for CORS headers regardless of the preflight (step 1 and step 3, respectively).
[...] Apply the make a request steps and observe the request rules below while making the request.
... (snipped: 3xx codes, aborts, and network errors)
Otherwise
Perform a resource sharing check. [...]
The resource sharing check algorithm for a given resource is as follows:
If the response includes zero or more than one Access-Control-Allow-Origin header values, return fail and terminate this algorithm.
[...]
The preflight request only prevents the "actual request" from beginning.

Keep getting No 'Access-Control-Allow-Origin' error with XMLHttpRequest

I would have solved this issue by using jQuery $.ajax function but in this case jQuery is not option. Instead I am going with CORS request. I feel there is something wrong with the webserver that is responding to the request and I am having a hard time figuring out what the issue is.
Here is my code for creating the CORS request
var httpRequest = new XMLHttpRequest();
httpRequest.open('POST', url, true);
httpRequest.setRequestHeader( 'Access-Control-Allow-Origin', '*');
httpRequest.setRequestHeader( 'Content-Type', 'application/json' );
httpRequest.onerror = function(XMLHttpRequest, textStatus, errorThrown) {
console.log( 'The data failed to load :(' );
console.log(JSON.stringify(XMLHttpRequest));
};
httpRequest.onload = function() {
console.log('SUCCESS!');
}
Here is the console.log error:
XMLHttpRequest cannot load
http://test.testhost.com/testpage. Request header field
Access-Control-Allow-Origin is not allowed by
Access-Control-Allow-Headers.
Here are the header information:
> Remote Address:**.**.***.**:80 Request
> URL:http://test.testdomain.com/testpage Request
> Request Method:OPTIONS
> Status Code:200 OK
Request Headers:
OPTIONS /content-network HTTP/1.1
Host: test.testhost.com
Connection: keep-alive
Cache-Control: no-cache
Pragma: no-cache
Access-Control-Request-Method: POST
Origin: http://test.testdomain.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36
Access-Control-Request-Headers: access-control-allow-origin, content-type
Accept: */*
Referer: http://test.testdomain.com/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Response Headers:
HTTP/1.1 200 OK
Date: Thu, 14 Aug 2014 20:17:25 GMT
Server: Apache
Last-Modified: Thu, 14 Aug 2014 20:17:25 +0000
Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0
ETag: "1408047445"
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Vary: Accept-Encoding
Content-Encoding: gzip
Access-Control-Allow-Headers: origin, x-requested-with, content-type
Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS
Content-Length: 6117
Connection: close
Content-Type: text/html; charset=utf-8
Your server's response allows the request to include three specific non-simple headers:
Access-Control-Allow-Headers:origin, x-requested-with, content-type
but your request has a header not allowed by the server's response:
Access-Control-Request-Headers:access-control-allow-origin, content-type
All non-simple headers sent in a CORS request must be explicitly allowed by the Access-Control-Allow-Headers response header. The unnecessary Access-Control-Allow-Origin header sent in your request is not allowed by the server's CORS response. This is exactly what the "...not allowed by Access-Control-Allow-Headers" error message was trying to tell you.
There is no reason for the request to have this header: it does nothing, because Access-Control-Allow-Origin is a response header, not a request header.
Solution: Remove the setRequestHeader call that adds a Access-Control-Allow-Origin header to your request.
Remove:
httpRequest.setRequestHeader( 'Access-Control-Allow-Origin', '*');
... and add:
httpRequest.withCredentials = false;
In addition to your CORS issue, the server you are trying to access has HTTP basic authentication enabled. You can include credentials in your cross-domain request by specifying the credentials in the URL you pass to the XHR:
url = 'http://username:password#test.testhost.com/testpage'
Enable CORS on backend server
or
add chrome extensions
https://chrome.google.com/webstore/search/CORS?utm_source=chrome-ntp-icon and make ON
We see this a lot with OAuth2 integrations. We provide API services to our Customers, and they'll naively try to put their private key into an AJAX call.
This is really poor security. And well-coded API Gateways, backends for frontend, and other such proxies, do not allow this. You should get this error.
I will quote #aspillers comment and change a single word: "Access-Control-Allow-Origin is a header sent in a server response which indicates IF the client is allowed to see the contents of a result".
ISSUE: The problem is that a developer is trying to include their private key inside a client-side (browser) JavaScript request. They will get an error, and this is because they are exposing their client secret.
SOLUTION: Have the JavaScript web application talk to a backend service that holds the client secret securely. That backend service can authenticate the web app to the OAuth2 provider, and get an access token. Then the web application can make the AJAX call.

Categories