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

Feature Request: Add negotiation (redirect, token) mechanism on client and server #4825

Open
zackliu opened this issue Sep 12, 2023 · 6 comments
Labels
enhancement New feature or request

Comments

@zackliu
Copy link

zackliu commented Sep 12, 2023

Feature description and some design details
It's a feature request about adding a negotiation mechanism.

  1. In server side, the negotiation can expose a path e.g. /negotiate and response a JSON:
{
  "url": "<url>",
  "token": "<token>"
}
  1. In the client side, we can expose a negotiate factory: new io(negotiateFactory: async () => await negotiateAsync()); And client read and parse the JSON, and then it can make connection according to the negotiation result.
  2. url is required for client to make connection and token can be set in Authorization header for long polling and access_token query string for websocket (websocket only support limited headers).
  3. The client does a new negotiation when reconnecting.
  4. This feature is optional in both server side and client side.

The reason why I want to add this feature
The feature benefits some scenarios:

  1. Clients need to be sharded into different groups of servers: Server or even just a negotiation server which only responsible for negotiation can use the negotiation mechanism to redirect the client to different
  2. token can be used to secure and auth the Engine.IO connection. Nowadays most of the auth is applied on Socket.IO level. But anyway an attacker can make Engine.IO connection without any auth to consume server's resource. Add a token upon Engine.IO connection and server can verify and reject it in io.engine.use() middleware. And negotiate every reconnection make sure you can refresh the token.
  3. Cloud provider scenarios: Cloud providers usually add a broker between client and servers. Add a negotiate let the server have chances to redirect clients to the cloud providers seamlessly. Consider clients enabled negotiate and the url point to the server directly first, and server can update and change it's negotiate result to redirect client to cloud provider (brokers) without changing any codes in clients.
@zackliu zackliu added the enhancement New feature or request label Sep 12, 2023
@zackliu
Copy link
Author

zackliu commented Sep 12, 2023

@darrachequesne I wonder whether you can have a look at this feature request. Is it OK to have such a data contract between client and server? And if we can have the agreement, I can take this issue and post a pull request.

@darrachequesne
Copy link
Member

@zackliu thanks for opening this 👍

I'm not sure if it should be integrated directly in the Socket.IO protocol. Maybe some kind of extension? Or as an additional package?

@zackliu
Copy link
Author

zackliu commented Sep 13, 2023

@darrachequesne Thanks for replying. I think for the server side, an extension may be enough as it only returns a negotiation response. But for the client side, it needs to be integrated into clients' constructing process. And as it's about connection not socket, maybe the change is more suitable in Engine.IO package.
The process for a new Engine.IO connection:

  1. If user assigned a negotiateFactory, library would execute the negotiateFactory and get the url and token
  2. Engine.IO set token to Authorization header for long polling and access_token query string for websocket.
  3. Make requests with url.

Every time it needs to reconnect, do the negotiation again.

As it changes the interior process, I think this has to change directly in Engine.IO package. Of course, it should be optional.

@darrachequesne
Copy link
Member

The process is very clear, thanks for the explanation 👍

Still, I'm not sure if we should add this feature to the client, because of the impact on the bundle size.

How about an additional package?

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

export async function createClient() {
  const socket = io({
    autoConnect: false,
  });

  // do the negotiation (upon initial setup and reconnection)

  socket.connect();

  return socket;
}

@zackliu
Copy link
Author

zackliu commented Sep 13, 2023

I'm not sure whether everything is achievable outside the class. E.g. For long polling the token should be in Authorization header but for websocket, it should be in query.
I have a proposal: can I create a PR in Engine.IO repo and invite you to review. If we have codes, we can more clearly estimate the impact on bundle size and discuss whether it's general enough to add in the client directly or having an extension is better.

@darrachequesne
Copy link
Member

can I create a PR in Engine.IO repo and invite you to review

Yes, sure! Having the code will surely help.

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

No branches or pull requests

2 participants