el_pup_le
el_pup_le

Reputation: 12179

Authenticating socket io connections using JWT

How can I authenticate a socket.io connection? My application uses a login endpoint from another server (python) to get a token, how can I get use that token whenever a user opens a socket connection on the node side?

io.on('connection', function(socket) {
    socket.on('message', function(message) {
        io.emit('message', message);
    });
});

And the client side:

var token = sessionStorage.token;
var socket = io.connect('http://localhost:3000', {
    query: 'token=' + token
});

If the token is created in python:

token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')

How can I use this token to authenticate a socket connection in node?

Upvotes: 177

Views: 198203

Answers (4)

Yilmaz
Yilmaz

Reputation: 49291

Write a middleware:

const jwt = require("jsonwebtoken");

const authSocketMiddleware = (socket, next) => {
  // since you are sending the token with the query
  const token = socket.handshake.query?.token;
  try {
    const decoded = jwt.verify(token, process.env.TOKEN_SECRET_KEY);
    socket.user = decoded;
  } catch (err) {
    return next(new Error("NOT AUTHORIZED"));
  }
  next();
};

module.exports = authSocketMiddleware;

Use it inside socket server

socketServer = (server) => {
  const io = require("socket.io")(server, {
    cors: {
      origin: "*",
      methods: ["GET", "POST"],
    },
  });
  // before connection use the middleware
  io.use((socket, next) => {
    authSocketMiddleware(socket, next);
  });
  io.on("connection", (socket) => {
    console.log("user connected", socket.id);
  });
};

Upvotes: 6

Muhammad Tameem Rafay
Muhammad Tameem Rafay

Reputation: 4575

Here I wrote the indepth article on how to authenticate the user on the sockets and also save the user's data

https://medium.com/@tameemrafay/how-to-authenticate-user-and-store-the-data-in-sockets-19b262496feb

CLIENT SIDE CODE

import io from "socket.io-client";

const SERVER = "localhost:4000";
const socket = io(SERVER, {
    auth: {
      token: "2c87b3d5412551ad69aet757f81f6a73eb919e5b02467aed419f5b2a9cce2b5aZOzgaM+bpKfjdM9jvez37RTEemAp07kOvEFJ3pBzvj8="
    }
  });

 socket.once('connect', (socketConnection) => {
    console.log('socket connected', socketConnection);
  })
 
// Emit the message and receive data from server in callback
 socket.emit("user send message", {message: "Hi you there" }, callback => {
    if (callback) {
      console.log("--- response from server", callback);
     }
  });

SERVER SIDE CODE

const initializeSockets = (io) => {
  io.on('connection', (socket) => {

  decryptAndStoreUserData(socket,io);
  
}

const decryptAndStoreUserData = async (socket,io) => {

    const { token } = socket.handshake.auth; // receive the token from client

    // here i decypt the auth token and get the user data
    const genToken = new Middlewares().token();
    const userData = genToken.decryptTokenForSockets(token);

    // save the data of user in socket
    socket.data.user = userData;

  }

Upvotes: 6

RJA
RJA

Reputation: 457

Since I don't have enough reputation to add a comment to accepted answer:

const socketioJwt = require('socketio-jwt');

Is not actually apart of auth0 's repo and is a third-party community based package.

Answer above should be updated as the link to auth0 repo is a page 404.

Upvotes: 9

hassansin
hassansin

Reputation: 17498

It doesn't matter if the token was created on another server. You can still verify it if you have the right secret key and algorithm.

Implementation with jsonwebtoken module

client

const {token} = sessionStorage;
const socket = io.connect('http://localhost:3000', {
  query: {token}
});

Server

const io = require('socket.io')();
const jwt = require('jsonwebtoken');

io.use(function(socket, next){
  if (socket.handshake.query && socket.handshake.query.token){
    jwt.verify(socket.handshake.query.token, 'SECRET_KEY', function(err, decoded) {
      if (err) return next(new Error('Authentication error'));
      socket.decoded = decoded;
      next();
    });
  }
  else {
    next(new Error('Authentication error'));
  }    
})
.on('connection', function(socket) {
    // Connection now authenticated to receive further events

    socket.on('message', function(message) {
        io.emit('message', message);
    });
});

Implementation with socketio-jwt module

This module makes the authentication much easier in both client and server side. Just check out their examples.

client

const {token} = sessionStorage;
const socket = io.connect('http://localhost:3000');
socket.on('connect', function (socket) {
  socket
    .on('authenticated', function () {
      //do other things
    })
    .emit('authenticate', {token}); //send the jwt
});

Server

const io = require('socket.io')();
const socketioJwt = require('socketio-jwt');

io.sockets
  .on('connection', socketioJwt.authorize({
    secret: 'SECRET_KEY',
    timeout: 15000 // 15 seconds to send the authentication message
  })).on('authenticated', function(socket) {
    //this socket is authenticated, we are good to handle more events from it.
    console.log(`Hello! ${socket.decoded_token.name}`);
  });

Upvotes: 355

Related Questions