Avag Sargsyan
Avag Sargsyan

Reputation: 2523

Reconnect disconnected socket.io with JWT authentication

I'm using a JWT to authenticate with socket.io. Here is the client code:

const socket = io.connect(
            'ws://123.456.789.0:8500',
            {
                query: {
                    token: jwtToken
                },
                transports: ['websocket', 'polling']
            }
        );

Now, at some point the jwtToken expires and the connection disconnected from the server:

...
io.on('connection', async (socket) => {
    const isExpired = await checkExpireDateEveryMinute(socket.exp, 5);

    if (isExpired) {
        socket.disconnect();
    }

    await socket.on('query', async (data) => {

        ...

    });
});

Which is the proper way to reconnect from client with new generated JWT token? Couldn't find much resources on this. Thanks.

Upvotes: 3

Views: 2506

Answers (1)

i.brod
i.brod

Reputation: 4623

I think a batter way is to use socket.io's middleware functionality, which will prevent the on("connection") callback from firing, if you call next() with an Error object. It will also transmit the error message to the frontend. You can send a fresh token this way, and reconnect.

Here is an example:

async function authenticate(socket,next){
    const isExpired = await checkExpireDateEveryMinute(socket.exp, 5);

    if(isExpired){
        const newToken = getNewToken()//Get a new token...
        next(new Error(newToken))//This will cause an error in your frontend, and pass the new token.
    }else{
        next();
    }
}
io.use(authenticate)//Register the middleware.

I have to point out something: you're doing "await" on socket.on(query,...), which makes no sense.

As for your frontend, it might look something like this:

function initSocket(token, url) {

  const socket = io.connect(url, {//Init the socket.
    query: {
      token
    }
  });

  return socket;
}

let socket = initSocket('someToken', 'http://localhost:8000')

socket.on('error', async (error) => {
  if(error === 'TOKEN_EXPIRED'){
    const newToken = await getToken();
    socket.close();
    socket = initSocket(newToken, 'http://localhost:8000')
  }
})

Note that you will need to re-register all events you have for your socket.

Upvotes: 4

Related Questions