Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

socket.io authentication after socket established

I'm working on a small multiplayer game. I'd like to introduce authentication. I'm using Node.js and Socket.io.

When the user arrives that the main page - I want them to join the game whether they are logged in or not - but they will be unable to do anything within it (only watch).

How could I then go about authenticating the user on the already open socket?

Could I maintain the authentication still if they left the site and came back? Can you pass a cookie through a web socket?

EDIT

To further my question. One of the possible thoughts I've had is to provide the websocket connection, then when they try to login in, it passes username and password as a message to the websocket.

client.on('onLogin', loginfunction);

I could then take the username and password, check against the database, then take the session ID of the socket and pass it somewhere to say that session is authenticated to that user.

Is this secure? Could I still implement a cookie on the socket so they could come back? Is there any way within socket.io of stating that the socket is now authenticated instead of manually checking on each message received?

Cheers

like image 711
Chris Evans Avatar asked Jan 06 '12 07:01

Chris Evans


People also ask

Does Socket.IO need authentication?

It is important to know that, by default, there is no authentication provided by Socket.io connections. Anyone can point a client at your server and start emitting and receiving events.

Does Socket.IO reconnect after disconnect?

Socket disconnects automatically, reconnects, and disconnects again and form a loop. #918.


1 Answers

This isn't actually too hard, but you're approaching it the wrong way. A couple things:

  1. You cannot set a cookie with socket.io; you can, however, get the cookie values of any connected client at any time. In order to set a cookie, you will have to send a new http response, meaning the user must first send a new http request (aka refresh or go to a new page, which it sounds is not a possibility for you here).

  2. Yes: socket.io is secure (to the extent that any transmitted data can be).

As such, you can do the following:

On the user's initial connection, create a cookie with a unique session ID, such as those generated from Express's session middleware. You will need to configure these not to expire on session end though (otherwise it will expire as soon as they close their browser).

Next you should create an object to store the cookie session IDs. Each time a new connect.sid cookie is set, store in your new object with a default value of false (meaning that the user has been authenticated by session, but not by logon)

On the user's login, send a socket emit to the server, where you can then authenticate the login credentials, and subsequently update the session id object you created to read true (logged in) for the current socket id.

Now, when receiving a new http request, read the cookie.sid, and check if its value in your object is true.

It should look something like the following:

var express = require('express'),
http = require('http'),
cookie = require('cookie');

var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);


app.use(express.cookieParser());
app.use(express.session({ 
    secret: 'secret_pw',
    store: sessionStore,
    cookie: { 
        secure: true,
        expires: new Date(Date.now() + 60 * 1000), //setting cookie to not expire on session end
        maxAge: 60 * 1000,
        key: 'connect.sid'
    }
}));

var sessionobj = {}; //This is important; it will contain your connect.sid IDs.

//io.set('authorization'...etc. here to authorize socket connection and ensure legitimacy


app.get("/*", function(req, res, next){
    if(sessionobj[req.cookies['connect.sid']]){
        if(sessionobj[req.cookies['connect.sid']].login == true){
            //Authenticated AND Logged in
        }
        else{
            //authenticated but not logged in
        }
    }
    else{
        //not authenticated
    }

});


io.sockets.on('connection', function(socket){
    sessionobj[cookie.parse(socket.handshake.headers.cookie)['connect.sid'].login = false;
    sessionobj[cookie.parse(socket.handshake.headers.cookie)['connect.sid'].socketid = socket.id;

    socket.on('login', function(data){
        //DB Call, where you authenticate login
        //on callback (if login is successful):
        sessionobj[cookie.parse(socket.handshake.headers.cookie)['connect.sid']] = true;
    });

    socket.on('disconnect', function(data){
        //any cleanup actions you may want
    });

});
like image 164
Ari Avatar answered Oct 19 '22 05:10

Ari