Getting lots of CORS errors after the latest update.
Repo. See README for instructions.
No CORS errors.
@davericher made a comment here indicating this. Perhaps he has more details.
+1 Started to fail since I downloaded the packages again.
Workaround: npm install socket.[email protected]
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.
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?
Yes. You need to have socket server on separate domain.
@darrachequesne : I updated my description with a link to repo where you can reproduce the issue. Instructions are in the README at the repo.
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:
The browser should stop complaining about the CORS violation then.
@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
?
@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.
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
@flenter could it be related to https://github.com/socketio/engine.io/pull/511?
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
https://github.com/socketio/engine.io/pull/511/files#diff-c945a46d13b34fcaff544d966cffcabaL259
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
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
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)
Wouldnt it make sense to have credentials off by default? For most cases it shouldnt be on anyway right?
@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 [email protected]
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.
Is there any ETA on bug fix release? 2.2.0 uses engine 3.3.1, not 3.3.2
@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.[email protected]
โ โโ debug@~4.1.0
โ โโ [email protected]
โ โ โโ ms@^2.1.1
โ โโ engine.io@~3.3.1
โ โโ has-binary2@~1.0.2
โ โโ [email protected]
โ โโ socket.io-adapter@~1.1.0
โ โโ socket.[email protected]
โ โโ socket.io-parser@~3.3.0
Well @ravid87,3.3.1 engine.io is "broken", while 3.3.2 is fixed :)
@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 suppliedorigins
; if not, all origins were allowed. In 2.2.0 (really new dep on[email protected]
via this commit I think), CORS is enforced whether or not you supply anorigins
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.
@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 :)
@neemah @ravid87 : sorry for confusion; correcting my typo by editing comment ...
@neemah : npm
should resolve correctly to [email protected]
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..
@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"
2) i don't understand why everything works with 3.3.1...
2 - probably because you are checking it on same domain, where this problem does not appear
@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 :/
then probably you configurated origin with value http[s]://foobar.com
where you run socket.foobar.net
@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...
@ravid87 : Can you confirm today you have [email protected]
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.
@sjones6 yes ! i have the 3.3.2 :+1: thx for the clarification :)
I Have same problem with CORS:
-- [email protected]
-- engine.[email protected]
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>
http://localhost:5530/
// ... 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.
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);
I have same issue..
Most helpful comment
Workaround: npm install socket.[email protected]