13

I'm trying to do a fetch from backbone.js to my node.js server. However, I get the following error in the console:

Origin http://localhost is not allowed by Access-Control-Allow-Origin.

I added the following to my node.js server:

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', "http://localhost");
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');
};

app.configure(function() {
    app.use(allowCrossDomain);
});

But it's still returning the same error. However, even if this did work, it doesn't seem like the ideal solution, as I would like users from all over to be able to send requests.

Willem Ellis
  • 4,886
  • 7
  • 38
  • 55
  • You may want to use '*' instead of http://localhost in that case. I'm not familiar with Node however, so I don't know if thats the answer or if its a configure issue. – ryanday Apr 16 '13 at 20:40
  • See if this helps http://stackoverflow.com/questions/15534640/ajax-origin-localhost-is-not-allowed-by-access-control-allow-origin/15537999#15537999 – PSL Apr 16 '13 at 20:47
  • @generalhenry You are wrong. [`http://localhost` is correct](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) and you should delete your comment to avoid confusion. – Daniel W. Aug 04 '14 at 09:01
  • what is app in app.configure? – Arj 1411 Aug 24 '16 at 06:19

5 Answers5

15

If you want everyone to be able to access the Node app, then try using

res.header('Access-Control-Allow-Origin', "*")

That will allow requests from any origin. The CORS enable site has a lot of information on the different Access-Control-Allow headers and how to use them.

I you are using Chrome, please look at this bug bug regarding localhost and Access-Control-Allow-Origin. There is another StackOverflow question here that details the issue.

Community
  • 1
  • 1
ryanday
  • 2,506
  • 18
  • 25
  • Is this a safe way to do it? I found [this](https://github.com/thomasdavis/backbonetutorials/blob/gh-pages/examples/cross-domain/server.js) regarding node, backbone, and cross-domain stuff. And it works, but every once in a while it will throw a 404, which I think may have something to do with the chrome bug. – Willem Ellis Apr 16 '13 at 21:09
  • 1
    It would be misleading to call this method "safe", however I've used it before in situations where every AJAX request carries its own authentication token. CORS is meant to prevent malicious folk from tricking your user's browser into accessing sensitive information from your application. You should, ideally, add a header for every possible legitimate location that your backbone application could be served from. – ryanday Apr 16 '13 at 21:21
  • What if i am using 3rd Party API ? I can't add "Allow Access" on their server. You are showing example of local project. I am having same issue but with my request is goes to another website url. How to fix it any idea ? – Gurpinder Apr 27 '16 at 09:16
  • CORS is designed specifically to prevent what you are trying to do :) There are security implications in some situations. What you can do instead is build a proxy for the 3rd party API. Your webapp queries your proxy, and your proxy makes calls to the 3rd party API. Now you have control over the header on your proxy, and your proxy is allowed to call the 3rd party API. – ryanday Apr 27 '16 at 12:51
0

If you are making the fetch call to your localhost which I'm guessing is run by node.js in the same directory as your backbone code, than it will most likely be on http://localhost:3000 or something like that. Than this should be your model:

var model = Backbone.Model.extend({
    url: '/item'
});

And in your node.js you now have to accept that call like this:

app.get('/item', function(req, res){
    res.send('some info here');
});
Stevo Perisic
  • 353
  • 2
  • 12
0

There are 2 calls that need to set the correct headers. Initially there is a preflight check so you need something like...

app.get('/item', item.list);
app.options('/item', item.preflight);

and then have the following functions...

exports.list = function (req, res) {
Items.allItems(function (err, items) {
    ...
        res.header('Access-Control-Allow-Origin', "*");     // TODO - Make this more secure!!
        res.header('Access-Control-Allow-Methods', 'GET,PUT,POST');
        res.header('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept');
        res.send(items);
      }
   );
};

and for the pre-flight checks

exports.preflight = function (req, res) {
Items.allItems(function (err, items) {
        res.header('Access-Control-Allow-Origin', "*");     // TODO - Make this more secure!!
        res.header('Access-Control-Allow-Methods', 'GET,PUT,POST');
        res.header('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept');
        res.send(200);
    }
  );
};

You can consolidate the res.header() code into a single function if you want.

Also as stated above, be careful of using res.header('Access-Control-Allow-Origin', "*") this means anyone can access your site!

mstreffo
  • 795
  • 2
  • 8
  • 20
0

By localhost you have to use the null origin. I recommend you to create a list of allowed hosts and check the request's Host header. If it is contained by the list, then by localhost send back an

res.header('Access-Control-Allow-Origin', "null");

by any other domain an

res.header('Access-Control-Allow-Origin', hostSentByTheRequestHeader);

If it is not contained by the list, then send back the servers host name, so the browser will hide the response by those requests.

This is much more secure, because by allow origin * and allow credentials everybody will be capable of for example stealing profile data of a logged in user, etc...

So to summarize something like this:

if (reqHost in allowedHosts)
    if (reqHost == "http://localhost")
        res.header('Access-Control-Allow-Origin', "null");
    else
        res.header('Access-Control-Allow-Origin', reqHost);
else
    res.header('Access-Control-Allow-Origin', serverHost);

is the most secure solution if you want to allow multiple other domains to access your page. (I guess you can figure out how the get the host request header and the server host by node.js.)

inf3rno
  • 24,976
  • 11
  • 115
  • 197
0

This approach resolved my issue to allow multiple domain

app.use(function(req, res, next) {
      var allowedOrigins = ['http://127.0.0.1:8020', 'http://localhost:8020', 'http://127.0.0.1:9000', 'http://localhost:9000'];
      var origin = req.headers.origin;
      if(allowedOrigins.indexOf(origin) > -1){
           res.setHeader('Access-Control-Allow-Origin', origin);
      }
      //res.header('Access-Control-Allow-Origin', 'http://127.0.0.1:8020');
      res.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
      res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
      res.header('Access-Control-Allow-Credentials', true);
      return next();
    });