socket.io: HttpOnly cookie is not getting set on the handshake request in Jest

Describe the bug I am using the React socket.io-client package to connect to a socket.io websocket. The authentication of the entire application is based on httpOnly cookies (i.e. these cookies can not be accessed through clientside Javascript).

When running the app in developement, everything works as expected: the socket client sets the httpOnly cookie on the handshake request and the server authenticates this.

But when running the Jest test suite, the httpOnly cookie no longer gets set on the handshake.

Note that when making http requests (using fetch) in Jest, the httpOnly cookie DOES get set as expected. So for whatever reason, the socket.io-client is not setting the httpOnly cookie on the handshake request in Jest…

Any help or suggestions would be greatly appreciated! Thank you

Socket.IO server version: ^3.1.0 Socket.IO client version: ^3.1.1

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 18 (6 by maintainers)

Commits related to this issue

Most upvoted comments

I believe this happens because we don’t get access to a response object in the middleware adapter

const wrap = middleware => (socket, next) => middleware(socket.request, {}, next)

The withCredentials only configures CORS to allow cookies to be sent by the client to the server. If these cookies have already been set by some HTTP route then these cookies are sent.

However if the cookies haven’t been set by an HTTP route, then socket.io is invoked without a cookie. The middleware does its job - it starts a new session and sets a cookie. But this is ignored by socket.io and the changes in response headers made by middleware are not propagated to response of the handshake request.

Currently, I see no way of customizing socket.io handshake behaviour (e.g. adding custom headers to be sent in the response), so I see this as a bug. (This used to be possible with some hacks in older versions of socket.io)

@driedger cookie management in Node.js was added in https://github.com/socketio/engine.io-client/commit/5fc88a62d4017cdc144fa39b9755deadfff2db34, included in version 4.7.0:

import { io } from "socket.io-client";

const socket = io("https://example.com", {
  withCredentials: true
});

I think we need to add a way to store cookies for the Node.js client. Let’s do this 👍

@darrachequesne Has there been any progress on storing the cookies for a node.js client?

I am having issues with a node.js socket.io-client connecting to a Traefik proxy using cookies for a sticky session. Connecting with a browser to the same entrypoint sets the cookie correctly, resulting in a polling connection successfully upgrading to a websocket. However, when the node.js client performs the same action with the same options (withCredentials: true), it fails to connect unless I limit the transports to websocket only.

To my knowledge, it still hasn’t… I guess most people don’t actually test frontends with a real socket server (/API). However, I actually do prefer to write my client-side tests this way. But for all my socket related things, I had to mock those responses as a way to work around this issue - unfortunately…

@peey thank you for your comment. Just to emphasize, the problem I described is specific to running tests in Jest. Everything works fine and as expected in development (and production)