I have a Jupyter KernelGatewayApp running on a VM instance in Google cloud. I defined an API which responds to a GET statement.
If I combine the ip address of the VM instance with the port of the Kernel Gateway and the GET statement with the right parameters, I get the desired result.
However, I would like to call the API using a javascript button on another site. This doesn't work as the browser is first sending an OPTIONS statement which I don't manage to respond to correctly.
Concretely, I have the following:
Running Jupyter Kernel Gateway on port 8888 : 33.44.567.789:8888
Working API : 33.44.567.789:8888/api?fname=john&lname=doe
Other website where a javascript button calls the above API : johndoe.me
Returns following error on requestor (browser) side:
XMLHttpRequest cannot load
http://33.44.567.789:8888/api?fname=john&lname=doe. Request header
field Content-type is not allowed by Access-Control-Allow-Headers in
preflight response.
Generates following message on server:
INFO:tornado.access:200 OPTIONS /api?fname=john&lname=doe
(xx.xxx.xx.xxx) 1.2 ms
Because of the thing I read here I added all different sort of parameters when launching the Jupyter Kernel Gateway:
jupyter kernelgateway --KernelGatewayApp.api='kernel_gateway.notebook_http' --KernelGatewayApp.seed_uri='/home/dummy_gmail_com/code/test_api.ipynb' --KernelGatewayApp.allow_origin='http://johndoe.me' --KernelGatewayApp.allow_methods='GET,OPTIONS,POST' --KernelGatewayApp.allow_credentials='true' --KernelGateway.allow_headers='Origin, X-Requested-With, Content-Type, Accept, content-type' --KernelGatewayApp.expose_headers='Origin, X-Requested-With, Content-Type,Accept' --KernelGatewayApp.answer_yes=True
The issue seems to be that the browser is issuing an OPTIONS instead of a GET but I'm not really sure. Is this linked to the cross origin fact ? Is there a way to handle this correctly or a way around this ?
Having had the same problem I found that CORS requests served by Jupyter Kernel Gateway worked with the following parameters:
jupyter kernelgateway --KernelGatewayApp.api='kernel_gateway.notebook_http' --KernelGatewayApp.seed_uri='/home/dummy_gmail_com/code/test_api.ipynb' --KernelGatewayApp.allow_origin='http://johndoe.me'
(Using OP's domains etc. for consistency.)
The parameter KernelGatewayApp.allow_origin='*' also worked/Solved the problem.
However I did go wrong prompted by the initial browser console error message which ran:
Access to fetch at 'http://localhost:8889/convert?degrees=164' from origin
'http://localhost:3000' has been blocked by CORS policy:
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.
This prompted me to set the request mode to 'no-cors'. The effect of this is to prevent an Origin header being sent with the request. Under these circumstances no amount of tinkering with the kernel gateway parameters resulted in a successful response.
Also when specifying the Allow Origin header as anything other than '*' it needs to be an exact string match to the 'Origin' header. For example:
Allow-Origin: http://127.0.0.1 does not match Origin: http://localhost
Allow-Origin: localhost does not match Origin: http://localhost
Allow-Origin: http://localhost/ does not match Origin: http://localhost
Allow-Origin: http://localhost does not match Origin: http://localhost:3000
etc.
as you can see with service /siteupdate, you can allow origin on a per service basis
Related
I'd like my Rails 5 API-only app, for now running on http://localhost:3000, to only accept requests from my NodeJS front-end app, for now running on http://localhost:8888.
So I configured /config/initializers/cors.rb like this:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins "http://localhost:8888"
resource "*",
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
And I wrote this test:
#/spec/request/cors_request_spec.rb
RSpec.feature "CORS protection", type: :request do
it "should accept a request from a whitelisted domain" do
get "/api/v1/bodies.json", nil, "HTTP_ORIGIN": "http://localhost:8888"
expect(response.status).to eql(200)
end
it "should reject a request from a non-whitelisted domain" do
get "/api/v1/bodies.json", nil, "HTTP_ORIGIN": "https://foreign.domain"
expect(response.status).to eql(406)
end
end
The first test is passing as expected. But the second is failing with a response code of 200. Why?
(I'm not wed to a 406 response code by the way; just one that indicates the request will not be fulfilled.)
CORS configuration won’t prevent the server from accepting requests based on the value of the Origin request header. You can’t do that just through CORS configuration.
When you configure CORS support on a server, all that the server does differently is just to send the Access-Control-Allow-Origin response header and other CORS headers.
Enforcement of CORS restrictions is done only by browsers. It’s not enforced by servers.
CORS works like is: regardless of any CORS config you make on the server side, the server continues accepting requests from all clients and origins it otherwise would; and so all clients from all origins continue getting responses from the server just as they otherwise would.
So even when you see an error in browser devtools that a cross-origin request from your frontend JavaScript code failed, you’ll still be able to see the response in browser devtools.
But just because your browser can see the response doesn’t mean the browser will expose it to your frontend code. Browsers only expose responses for cross-origin requests to frontend code running at a particular origin if the server the request went to opts-in to allowing the request by responding with an Access-Control-Allow-Origin header which OKs that origin.
So for any requests with an Origin request header matching https://foreign.domain, the configuration snippet in the question should cause browsers to emit a message on the client side saying http://localhost:3000/api/v1/bodies.json can’t be loaded because there’s no Access-Control-Allow-Origin response header in the response (because your configuration causes the server to only send that header in responses to your whitelisted origins).
But that’s all you can do through CORS. You can’t prevent the server side from accepting and responding to requests from particular origins just by doing any CORS configuration on the server side. If you want to do that, you need to do it using something other than just CORS.
I am using the node module #googlemaps/google-maps-services-js to make requests to the Google maps API. When I make requests to any of their API endpoints (e.g directions API, places API, etc), I get these errors:
xhr.js:125 Refused to set unsafe header "User-Agent"
xhr.js:125 Refused to set unsafe header "Accept-Encoding"
localhost/:1 Access to XMLHttpRequest at 'https://maps.googleapis.com/maps/api/directions/json?
destination=Universal%20Studios%20Hollywood&key=mykey&origin=Disneyland' from
origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header
is present on the requested resource.
Here are the things I've tried:
1. I've tried accessing different API endpoints, (e.g instead of directions, places.)
2. I've tried adding headers manually, but I don't really know what headers i should add to make this work.
3. I have also tried accessing this API from my normal browser (Google). It returned a proper response, so it isn't an improper API key.
Also Note:
I have activated my API key, activated each of the APIs I want to use, and I have set up a billing account with Google Cloud Platform.
Not for browser
#googlemaps/google-maps-services-js is not compatible with browser environments because the Google server DOES NOT return the necessary CORS headers. This package is for Nodejs.
From the readme:
Alternative [Preferred]
Use https://developers.google.com/maps/documentation/javascript/overview.
Your code will look similar to the following:
const directionsService = new google.maps.DirectionsService();
const request = {
origin: 'Disneyland',
destination: 'Universal Studios Hollywood',
travelMode: 'DRIVING'
};
const response = await directionsService.route(request);
A directions tutorial is available.
Alternative 2
Proxy the directions endpoint through your own server and add CORS headers.
are you using cors on your endpoint?
you should allow your endpoint to respond to a different origin (this is why is Cross Origin, because it is different from the location of your endpoint).
here you can find a good/simple example of using cors policy in nodejs
Ionic 2
I am using login provider but when i set the access control to
res.header('Access-Control-Allow-Origin', '*');
It is not working
But it works properly when i use
res.header('Access-Control-Allow-Origin', 'http://localhost:8100');
It is working
but now i want to deploy my app up on phone device i need to set it to wild card res.header('Access-Control-Allow-Origin', '*');. since my app on phone not working on http://localhost:8100 anymore
Anyone can help me solve this problem ?
If you are making a preflighted request then the wildcard is forbidden in the Access-Control-Allow-Origin header.
You can read the Origin request header in order to find out the origin. Then you can test it against a list of allowed origins (you could also assume that any origin is OK, but for a preflighted request there is a good chance that complete public access would be a security risk). Finally you can copy it into the Access-Control-Allow-Origin response header.
How is your HTTP request from your app looks like?
Look for "Types of CORS requests" in this article.
If your HTTP request is a simple one, i.e.
Method is HEAD, GET, or POST
Only have these headers
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type of application/x-www-url-encoded, multipart/form-data, or text/plain
If your HTTP request is a simple one, preflight is not needed. And Access-Control-Allow-Origin with * is accepted by the mobile app.
Otherwise, a preflight request will be made (i.e. OPTION request) and Access-Control-Allow-Origin of * will be ignored. It must be fully specified like http://localhost:8100.
I am developing an ajax form update on localhost in express.js for learning express.js
The origin in header is alway set to be null by browser for CORS request (tried: firefox, chrome and safari)
Question:
1. "Origin: null" in request header is not the problem of express.js. Is this correct?
Why they(is it the browsers?) set the Origin to null? I think it should look like this one: "localhost:3000/myproject/test/form.html"
Should I use jquery ($.ajax() or $.ajaxSetup()) to set the origin, before calling ajax on localhost?
How to make the origin in header reflect the real situation?
Here is the screenshot: [...the screenshot is gone now...]
I read the following article about the CORS. The origin in header is null, which is not explained. Please help.
http://www.html5rocks.com/en/tutorials/cors/
"The first thing to note is that a valid CORS request always contains an Origin header. This Origin header is added by the browser, and can not be controlled by the user."
How to allow CORS?
The Origin header is null because you are making the CORS request from a local file (I bet the url starts with file://). In order to get a "normal" origin, you need to host the client file on a web server and access that file using http or https.
Also note that the Origin value is set by the browser and can not be overridden by client JavaScript code.
(P.S. I wrote that HTML Rocks article, I'll make a note to add a section about null Origin)
I made the simple hello world NODEJS Server.
I have a enyo web service running in chrome that is trying to access the NODEJS server at http://localhost:3000
When is calls the onSuccess method, no data is loaded and the consule shows the following error
XMLHttpRequest cannot load http://localhost:3000/. Origin http://localhost:81 is not allowed by Access-Control-Allow-Origin.
I tested the nodejs server in the browser, it worked fine.
I tried to set the --disable-web-security, flag in chrome, it did not work.
Does anybody know how to fix this problem? If NOD.js is running on another server, would it work? This security is so confusing.
Ted
For security reasons, browsers limit the requests that a script may make via XMLHttpRequest.
Your requests will only succeed under the following 2 cases:
The origin of the URI that your script loads is the same as the origin of the page on which the script is executing (localhost:81 and localhost:3000 are the same host but different origins);
or, if your browser supports it, the server of the page being requested includes an Access-Control-Allow-Origin header which explicitly authorizes pages served from the origin in question (or pages served from all origins) to make XMLHttpRequests to it.
Try adding the Accesss-Control-Allow-Origin header to whatever is generating the response in your node code, adding a header in some code that looks like this:
response.writeHead(200, {
'Content-Type': 'text/plain',
'Access-Control-Allow-Origin' : 'http://localhost:81'
//allow anything by replacing the above with
//'Access-Control-Allow-Origin' : '*'
});