Rav Som
Rav Som

Reputation: 21

Express JS CORS when requested via browser

While using an Express/NodeJS backend - I have a REST GETTER that is used to authenticate using strava (passport-strava)

When I invoke the API URL directly(http://localhost:3000/api/auth/strava) - the connection is successful and I'm able to retrieve the profile information. However, when this is invoked through a browser widget, i.e. onClick of a HTML button and routed through to the backend - I'm thrown an error

XMLHttpRequest cannot load https://www.strava.com/oauth/authorize?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fstrava%2Fcallback&client_id=9769. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.

I do understand that this is related to CORS and that the header "Access-Control-Allow-Origin" must be included however, there is no respite on adding this into the header with the appropriate value.

I tried to intercept the calls using chrome://net-internals to check if Access-Control-Allow-Origin is being stripped out and noticed the variations in calls -

When called directly via the API - the calls are as follows

1097271 URL_REQUEST http://localhost:3000/api/auth/strava
1097273 DISK_CACHE_ENTRY    http://localhost:3000/api/auth/strava
1097275 HTTP_STREAM_JOB https://www.strava.com/
1097276 CONNECT_JOB ssl/www.strava.com:443
1097277 CONNECT_JOB ssl/www.strava.com:443
1097278 SOCKET  ssl/www.strava.com:443
1097279 CONNECT_JOB ssl/www.strava.com:443
1097280 CONNECT_JOB ssl/www.strava.com:443
1097281 SOCKET  ssl/www.strava.com:443
1097282 DISK_CACHE_ENTRY    https://www.strava.com/oauth/authorize?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fstrava%2Fcallback&client_id=9769
1097283 HTTP_STREAM_JOB https://www.strava.com/
1097285 URL_REQUEST http://localhost:3000/api/auth/strava
1097288 DISK_CACHE_ENTRY    http://localhost:3000/api/auth/strava
1097290 HTTP_STREAM_JOB https://www.strava.com/
1097291 DISK_CACHE_ENTRY    https://www.strava.com/oauth/authorize?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fstrava%2Fcallback&client_id=9769
1097292 HTTP_STREAM_JOB https://www.strava.com/
1097293 DISK_CACHE_ENTRY    http://localhost:3000/api/auth/strava/callback?state=&code=7b5722c72f079ee2ac5dfeb7d5140cdc6375f5cc

However, when routed via the widget the calls are as follows

1097337 URL_REQUEST http://localhost:3000/api/auth/strava
1097339 DISK_CACHE_ENTRY    http://localhost:3000/api/auth/strava
1097344 URL_REQUEST https://www.strava.com/oauth/authorize?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fstrava%2Fcallback&client_id=9769
1097346 DISK_CACHE_ENTRY    https://www.strava.com/oauth/authorize?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fstrava%2Fcallback&client_id=9769
1097347 HTTP_STREAM_JOB https://www.strava.com/
1097348 CONNECT_JOB pm/ssl/www.strava.com:443
1097349 CONNECT_JOB pm/ssl/www.strava.com:443
1097350 HOST_RESOLVER_IMPL_JOB  www.strava.com
1097352 SOCKET  pm/ssl/www.strava.com:443
1097353 CONNECT_JOB pm/ssl/www.strava.com:443
1097354 SOCKET  pm/ssl/www.strava.com:443

The difference that I seemed to pull out is the additional call

1097344 URL_REQUEST https://www.strava.com/oauth/authorize?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fstrava%2Fcallback&client_id=9769

which isn't made in the previous scenario.

These observations are made not only for the passport-strava package but the passport-facebook package as well. Therefore, I think there is something gravely incorrect that I'm doing to get into this state.

Any assistance is well appreciated.

Upvotes: 0

Views: 450

Answers (1)

Samuel Toh
Samuel Toh

Reputation: 19248

Since you already know about CORS then I go into any details.

Basically your issue is with your REST server, it needs to set the response packet's header with the appropriate content so that the browser doesn't complain. Unfortunately this is a security feature.

So in your server code, you need to define a function that would do the above and set it as 1 of the middleware layer that express will have to parse when a HTTP comes through.

Example:

var express = require('express');
var app = express();

var httpAccessControlPolicy = function(req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
  res.setHeader('Access-Control-Allow-Headers', 'Content-type,Accept,X-Access-Token,X-Key,Authorization');
  res.setHeader('Access-Control-Allow-Credentials', false);

  next();
};

app.use(httpAccessControlPolicy);

Yes. As pointed out by 1 of the commenter the npm module cors can also do the job.

CORS: https://www.npmjs.com/package/cors

If you are intending to use it then you might be looking at this example usage:

var express = require('express')
  , cors = require('cors')
  , app = express();

app.use(cors());

app.get('/products/:id', function(req, res, next){
  res.json({msg: 'This is CORS-enabled for all origins!'});
});

app.listen(80, function(){
  console.log('CORS-enabled web server listening on port 80');
});

Upvotes: 1

Related Questions