Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CORS Errors after updating to 2.2.0 #3381

Closed
1 of 2 tasks
sjones6 opened this issue Nov 29, 2018 · 37 comments
Closed
1 of 2 tasks

CORS Errors after updating to 2.2.0 #3381

sjones6 opened this issue Nov 29, 2018 · 37 comments

Comments

@sjones6
Copy link

sjones6 commented Nov 29, 2018

You want to:

  • report a bug
  • request a feature

Current behaviour

Getting lots of CORS errors after the latest update.
screen shot 2018-11-29 at 1 13 25 pm

Steps to reproduce (if the current behaviour is a bug)

Repo. See README for instructions.

Expected behaviour

No CORS errors.

Setup

  • OS: Mac
  • browser: Chrome 70
  • socket.io version: 2.2.0

Other information (e.g. stacktraces, related issues, suggestions how to fix)

@davericher made a comment here indicating this. Perhaps he has more details.

@Bramzor
Copy link

Bramzor commented Nov 29, 2018

+1 Started to fail since I downloaded the packages again.

@Bramzor
Copy link

Bramzor commented Nov 29, 2018

Workaround: npm install socket.io@2.1.1

@xaviergonz
Copy link

xaviergonz commented Nov 29, 2018

The funny thing is that I'm using a custom origins callback and it returns "*" as allowed origin instead of the actual origin passed from the client when the callback is called with success set to true.
On 2.1 it used to return the origin header passed from the client.

@darrachequesne
Copy link
Member

Hmm.. I don't see anything related in the changelog... It may be the update of the ws package.

Is anyone able to reproduce the issue?

@neemah
Copy link

neemah commented Nov 29, 2018

Yes. You need to have socket server on separate domain.

@sjones6
Copy link
Author

sjones6 commented Nov 29, 2018

@darrachequesne : I updated my description with a link to repo where you can reproduce the issue. Instructions are in the README at the repo.

@sjones6
Copy link
Author

sjones6 commented Nov 29, 2018

Another way to solve: fill in the origin property in your socketio server config:

const Server = require('socket.io');
const io = new Server({
  origins: 'http://your-cors-url' // i believe can also be an array of urls, defaults to '*'
});

You should see this show up in the response headers for the handshake request in your network tab:
screen shot 2018-11-29 at 4 10 28 pm

The browser should stop complaining about the CORS violation then.

@sjones6
Copy link
Author

sjones6 commented Nov 29, 2018

@darrachequesne It seems like if you comment out these lines in engine.io-client:

if ('withCredentials' in xhr) {
  xhr.withCredentials = true;
}

then the requests succeed.

So maybe, in v <2.2.0, somehow 'withCredentials' in xhr === false?

@darrachequesne
Copy link
Member

darrachequesne commented Nov 29, 2018

@sjones6 thanks for the repo. What I don't understand is that your example is a basic CORS situation, where the client is served from a location (localhost:3001) different from the server (localhost:3000). That shouldn't work in the previous versions either, and is solved with the origins parameter, as you pointed out.

@xaviergonz
Copy link

xaviergonz commented Nov 29, 2018

I think with credentials was always set to true.

The problem is that allow origins * is not allowed when with credentials is set to true. Previous versions would use the client origin (or referer if missing) header when an origin was valid, but the new version just uses "*", and therefore the browser complains.

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSNotSupportingCredentials

@darrachequesne
Copy link
Member

@flenter could it be related to socketio/engine.io#511?

@xaviergonz
Copy link

Another option is of course to set with credentials to false, but that'd mean that the socket io server does not care about getting / setting any cookies. Not sure if that's the case with socket io

@xaviergonz
Copy link

That pr could have added a way to set the header to the client request origin header. Maybe a good place to do this is that when using origins with a callback and the callback is called with success true the Allow-origins would be set to the origin that was passed to the callback.

Either way, after that PR this is a breaking change though I guess?

As it is right now I see no way to support all origins when with credentials is set to true

darrachequesne added a commit to socketio/engine.io that referenced this issue Nov 29, 2018
@darrachequesne
Copy link
Member

I reverted the PR and published a new version of engine.io. Could you please check that it fixes the issue? https://github.com/socketio/engine.io/commits/master

@xaviergonz
Copy link

Or to avoid a breaking change then when origins is not explicitly set in the options / set to undefined (default) or origins function is called with undefined then it will use the client origin header (the old default behavior)

@Bramzor
Copy link

Bramzor commented Nov 30, 2018

Wouldnt it make sense to have credentials off by default? For most cases it shouldnt be on anyway right?

@sjones6
Copy link
Author

sjones6 commented Nov 30, 2018

@darrachequesne : Thanks; we've pulled down 3.3.2 of engine.io and things are back in our environments.

Based on this comment this comment from @xaviergonz , I think I have a clearer picture:

In socket.io <2.2, CORS was enforced only if you supplied origins; if not, all origins were allowed. In 2.2.0 (really new dep on engine.io@3.3.1 via this commit I think), CORS is enforced whether or not you supply an origins options.

I'm all for enforcing CORS as default behavior ... but seems like that's probably a breaking change that should be added in new major version.


latest edit to correct errant version number of engine.io.

@neemah
Copy link

neemah commented Nov 30, 2018

Is there any ETA on bug fix release? 2.2.0 uses engine 3.3.1, not 3.3.2

@ravidhu
Copy link

ravidhu commented Nov 30, 2018

@neemah i had to remove and add socket.io to have the updated version :
yarn remove socket.io && yarn add socket.io

here my yarn list now :
├─ socket.io@2.2.0
│ ├─ debug@~4.1.0
│ ├─ debug@4.1.0
│ │ └─ ms@^2.1.1
│ ├─ engine.io@~3.3.1
│ ├─ has-binary2@~1.0.2
│ ├─ ms@2.1.1
│ ├─ socket.io-adapter@~1.1.0
│ ├─ socket.io-client@2.2.0
│ └─ socket.io-parser@~3.3.0

@neemah
Copy link

neemah commented Nov 30, 2018

Well @ravid87,3.3.1 engine.io is "broken", while 3.3.2 is fixed :)

@ravidhu
Copy link

ravidhu commented Nov 30, 2018

@neemah the broken one was 3.2.2

@darrachequesne : Thanks; we've pulled down 3.2.2 of engine.io and things are back in our environments.

Based on this comment this comment from @xaviergonz , I think I have a clearer picture:

In socket.io <2.2, CORS was enforced only if you supplied origins; if not, all origins were allowed. In 2.2.0 (really new dep on engine.io@3.2.1 via this commit I think), CORS is enforced whether or not you supply an origins options.

I'm all for enforcing CORS as default behavior ... but seems like that's probably a breaking change that should be added in new major version.

@neemah
Copy link

neemah commented Nov 30, 2018

@ravid87 3.2.2 doesn't exist https://github.com/socketio/engine.io/tree/3.2.2, so i assume author of message meant 3.3.2, which is latest release, if you check commits / tags.

So still waiting for fix :)

@sjones6
Copy link
Author

sjones6 commented Nov 30, 2018

@neemah @ravid87 : sorry for confusion; correcting my typo by editing comment ...

@sjones6
Copy link
Author

sjones6 commented Nov 30, 2018

@neemah : npm should resolve correctly to engine.io@3.3.2 based on the deps in socket.io:

"engine.io": "~3.3.1"

You need to delete your package-lock.json (or yarn.lock) first though before installing of you'll get 3.3.1 again..

@ravidhu
Copy link

ravidhu commented Nov 30, 2018

@sjones6 ok thx for the version correction. But i'm still confused because,

  1. even if i delete yarn.lock, i have this in my yarn.lock after a clean install ( yarn remove socket.io, yarn clean cache, yarn add socket.io ) :

socket.io@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.2.0.tgz#f0f633161ef6712c972b307598ecd08c9b1b4d5b"
integrity sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w==
dependencies:
debug "~4.1.0"
engine.io "~3.3.1"
has-binary2 "~1.0.2"
socket.io-adapter "~1.1.0"
socket.io-client "2.2.0"
socket.io-parser "~3.3.0"

  1. i don't understand why everything works with 3.3.1...

@neemah
Copy link

neemah commented Nov 30, 2018

2 - probably because you are checking it on same domain, where this problem does not appear

@ravidhu
Copy link

ravidhu commented Nov 30, 2018

@neemah here my setup :
-> the react app is served from foobar.com
-> the socket is on socket.foobar.net

so its not on same domain :/

@neemah
Copy link

neemah commented Nov 30, 2018

then probably you configurated origin with value http[s]://foobar.com where you run socket.foobar.net

@ravidhu
Copy link

ravidhu commented Nov 30, 2018

@neemah no origins configured on socket.io or express.js.

i had CORS problem yesterday and today after a clean install of socket.io everything worked again...

@sjones6
Copy link
Author

sjones6 commented Nov 30, 2018

@ravid87 : Can you confirm today you have engine.io@3.3.2 on your file system today? Based on your comment, the dependency on engine.io "~3.3.1" is correct but the downloaded version should be resolved to 3.3.2 not 3.3.1. Yesterday, it would have been 3.3.1 until the update was published.

yarn list --pattern engine.io --depth=5 should tell you.

@ravidhu
Copy link

ravidhu commented Dec 2, 2018

@sjones6 yes ! i have the 3.3.2 👍 thx for the clarification :)

@AhCamargo
Copy link

I Have same problem with CORS:

-- socket.io@2.3.0 -- engine.io@3.4.0

@cmmash
Copy link

cmmash commented Feb 6, 2020

Having the same problem as @AhCamargo responded, with the same versions of socket.io and engine.io, but mine is that I'm trying to open a socket.io connection with auth from a different domain (client side) than the server side

Full error context:

Server side versions:

    "socket.io": "^2.3.0",
    "engine.io": {
      "version": "3.4.0"

Client side versions:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
  1. Client at: http://localhost:5530/
    Client code:

      // ... get sessionToken, initialize stuff.

      var socket = io.connect('http://localhost:8011', {
        query: query,
        transportOptions: {
          polling: {
            extraHeaders: {
              'x-user-token': sessionToken
            }
          }
        }
      });

      socket.on('connect', () => {
        console.log("===> rootNspDemo connection established!!!!!, socket: ", socket.id);
      })
      socket.on('disconnect', (reason) => {
        console.log('rootNspDemo connection disconnected: ' + reason);
        socket.close(); // stop reconnecting
      })
      socket.on(topic, function(data) {
          console.log("###> root namespace progress data: ", data);
          document.getElementById("taskStatus").innerHTML = data.taskStatus;
      });
    }

The server side:

// ... imports


// Initialize express
const app = express();

// TRIED ALL THESE, BUT NONE WORK
// const cors = require('cors');
// app.use(cors({credentials: true, methods: ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'OPTIONS']}));
// app.options('*', cors({credentials: true, methods: ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'OPTIONS']}));
// app.use(cors());
// app.options('*', cors({methods: ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'OPTIONS']}));

const server = app.listen(SERVER_PORT, () => {
    logInfo(
      `%s v%s listening on port %s in %s mode`,
      PKG.name,
      PKG.version,
      SERVER_PORT,
      ENV
    );
  });


// var socketIOAllowedOrigins = "http://localhost:* http://127.0.0.1:*";
var socketIOAllowedOrigins = "http://localhost:5530";

// TRIED THIS ALSO, DIDN'T WORK
// const io = require('socket.io').listen(server, {origins: socketIOAllowedOrigins});

const socketIOAuth = async function(socket, next) {
  const sessionToken = socket.handshake.headers['x-user-token'];
  const user = await getUser(sessionToken);
  if (!user) {
  // eslint-disable-next-line no-console
    console.log('---> socket ' + socket.id + ' of nsp: ' + socket.nsp.name + ' FAILED authentication !!');
    socket.disconnect('unauthorized');
    next(new Error('invalid sessionToken'));
  } else {
  // eslint-disable-next-line no-console
    console.log('---> socket ' + socket.id + ' of nsp: ' + socket.nsp.name + ' is authenticated!!');
  }

  return next();
};

const io = require('socket.io').listen(server);
io.use(socketIOAuth); // REMOVING THIS, and NOT SENDING AUTH TOKEN FROM CLIENT, THEN IT WORKS
// io.origins('*');

io.origins(['localhost:8011', 'localhost:5530',
  'http://localhost:8011', 'http://localhost:5530']);

const runDemo = (socket) => {
    // Demo test of progress bar
    // eslint-disable-next-line no-console
    console.log('Running socket.io demo for topic: ', socket.handshake.query.topic);
    let i = 0;
    const interval = setInterval(function() {
      if (i < 100) {
        socket.emit(socket.handshake.query.topic, { rootDummy: true, progress: i, taskStatus: 'RUNNING' });
        i++;
      } else {
        socket.emit(socket.handshake.query.topic, { rootDummy: true, progress: i, taskStatus: 'SUCCESS' });
        clearInterval(interval);
      }
    }, 1000);
  }

io.on('connection', runDemo);

Here's the interesting bits I debugged:

Removing auth middleware from socketio in server side - io.use(socketIOAuth); and also removing the passing of sessionToken from client side :

        transportOptions: {
          withCredentials: true,
          polling: {
            extraHeaders: {
              // 'x-user-token': sessionToken
            }
          }
        }

Makes the connection work fine.

I can see the error log in nginx as the following:

"06/Feb/2020:21:36:44 +0530" client=127.0.0.1 method=OPTIONS request="OPTIONS /socket.io/?topic=rootNspDemo&demo=true&EIO=3&transport=polling&t=N0RGEpG HTTP/1.1" request_length=574 status=400 bytes_sent=326 body_bytes_sent=54 referer=http://localhost:5530/ user_agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" upstream_addr=127.0.0.1:8011 upstream_status=400 request_time=0.005 upstream_response_time=0.004 upstream_connect_time=0.000 upstream_header_time=0.000

curl gives me:

 curl -XOPTIONS 'http://local-messaging.onupkeep.com/socket.io/?topic=rootNspDemo&demo=true&EIO=3&transport=polling&t=N0RNF8q' -H 'Accept: */*' -H 'x-user-token: r:b33a941138a226f0fd37a9ea51c24c16' -H 'Referer: http://localhost:5530/' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36' --compressed
{"code":2,"message":"Bad handshake method"}

Which is in accordance with the explanation here: https://stackoverflow.com/a/52048304/11626829

Basically the browser is sending the options pre-flight request, but that is taken up by socket.io as a handshake request.

@vicky-gonsalves
Copy link

vicky-gonsalves commented Mar 12, 2020

I have same issue..

const options = { transportOptions: { polling: { extraHeaders: { 'x-auth-token': accessToken }, }, } }; socket = socketIOClient(config.socketUrl, options);

It works fine when I send it with query params:

const options = { query:{ auth_token: accessToken } }; socket = socketIOClient(config.socketUrl, options);

@brunobrante
Copy link

I have same issue..

@darrachequesne
Copy link
Member

For future readers: this was fixed in engine.io@3.3.2 (the change was reverted)

Please see the documentation here: https://socket.io/docs/v3/handling-cors/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants