2

I am trying to access the session from sockets, but can't seem to make a connection. Without fail, authorization fails and I get the fail callback with the following message:

failed connection to socket.io: No session found

I will place all my code here so that it might be easier to spot what I'm doing wrong.

var express  = require('express');
var app      = express();
var http     = require('http');
var socketio = require('socket.io')
var passportSocketIo = require('passport.socketio');
var port     = process.env.PORT || 3000;
var mongoose = require('mongoose');
var passport = require('passport');
var flash    = require('connect-flash');

var morgan       = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser   = require('body-parser');
var session      = require('express-session');
var MongoStore   = require('connect-mongo')(session);

var server   = http.createServer(app);
var io       = socketio.listen(server);

var dbConfig = require('./config/database.js');
mongoose.connect(dbConfig.url);
var sessionStore = new MongoStore({ db: mongoose.connection.db });

require('./config/passport')(passport);

app.use(morgan('dev'));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.set('view engine', 'ejs');

app.use(session({
    key: 'connect.sid',
    secret: 'secret',
    store: sessionStore,
    resave: true,
    saveUninitialized: true
}));

app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use(express.static(__dirname + '/public'));

require('./app/routes.js')(app, passport);

server.listen(3000, function() {
    console.log('App running on port: ' + port);
});

io.use(passportSocketIo.authorize({
    passport:     passport,
    cookieParser: cookieParser,
    key:          'connect.sid',
    secret:       'secret',
    store:        sessionStore,
    success:      onAuthorizeSuccess,
    fail:         onAuthorizeFail
}));

function onAuthorizeSuccess(data, accept){
  console.log('successful connection to socket.io');
  accept(null, true);
}

function onAuthorizeFail(data, message, error, accept){
  if(error)
    throw new Error(message);
  console.log('failed connection to socket.io:', message);
  accept(null, false);
}

io.sockets.on('connection', function(socket) {
    var date = new Date();
    var time = date.getHours() + ":" + date.getMinutes();
    socket.emit('message', {username: 'Server', message: 'welcome to the chat'});
    socket.on('send', function(data) {
        io.sockets.emit('message', data);
    });
});

How should I be establishing a connection to the session with socket.io?

Also, I have seen that the user data is accessed via socket.handshake.user. Would that be correct in this case?

And for clarity, the versions are as follows:

express: 4.8.5
passport: 0.2.0
socket.io: 1.0.6
passport.socketio: 3.2.0

EDIT

It appears that part of the issue was the localhost versus 127.0.0.1 bug that already exists. However, now I don't get any handshake data back.

laggingreflex
  • 32,948
  • 35
  • 141
  • 196
Wesley Porter
  • 1,401
  • 2
  • 13
  • 15

5 Answers5

3

First off, as I had noted in my question edit, be sure to type in the IP directly, rather than using localhost: 127.0.0.1. This is a known bug that will not allow you to send the cookie over correctly when pointing to localhost.

The passport-socketio Github page was, at last, updated with the following for the authorization callbacks for socket.io 1.x.

function onAuthorizeSuccess(data, accept){
  console.log('successful connection to socket.io');
  accept();
}

function onAuthorizeFail(data, message, error, accept){
  console.log('failed connection to socket.io:', data, message);
  if(error)
    accept(new Error(message));
}

Also, the handshake data is no longer stored in the same place. Replace socket.handshake.user with socket.request.user.

Wesley Porter
  • 1,401
  • 2
  • 13
  • 15
1

I had the exact same problem. For me the solution was not in the web server but due to calling localhost in the browser. Changing to 127.0.0.1 or to my acctual IP made life much happier.

See also answer and comments to: Javascript document.cookie always empty string

Community
  • 1
  • 1
northmoose
  • 139
  • 1
  • 1
  • 6
  • See my edit from August 25th. I still don't get any handshake data back. I believe this might be a bug in the current versions of the packages. – Wesley Porter Sep 25 '14 at 14:34
  • 1
    Sorry, didn't see that Edit. About the handshake, from socket.io > v1.0 socket.handshake.user is changed to socket.request.user. See https://github.com/jfromaniello/passport.socketio – northmoose Sep 25 '14 at 18:19
  • That was it! Thanks for catching that! – Wesley Porter Sep 25 '14 at 20:25
0

passport.socketio doesn't work with the new version of socket.io.

You should be able to remove passport.socketio and replace your current io.use with this one :

var cookieParser = require('cookie-parser')('secret'); // <- your secret here
io.use(function(socket, next){
    cookieParser(socket.handshake, {}, function(err){
        if (err) {
            console.log("error in parsing cookie");
            return next(err);
        }
        if (!socket.handshake.signedCookies) {
            console.log("no secureCookies|signedCookies found");
            return next(new Error("no secureCookies found"));
        }
        sessionStore.get(socket.handshake.signedCookies["connect.sid"], function(err, session){
            socket.session = session;
            if (!err && !session) err = new Error('session not found');
            if (err) {
                 console.log('failed connection to socket.io:', err);
            } else {
                 console.log('successful connection to socket.io');
            }
            next(err);
        });
    });
});
Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • With this, I am getting the following error: `failed connection to socket.io: [Error: session not found]`. There is no member `signedCookies` of `socket.handshake`. Any ideas why? – Wesley Porter Sep 01 '14 at 21:45
  • @WesleyPorter Do you establish a session with passport before connecting to socket.io ? I lack time right now to go deeper but here's how I do it in my application : https://github.com/Canop/miaou/blob/master/libs/ws.js#L474 – Denys Séguret Sep 02 '14 at 06:57
  • Isn't that what the line in my code above does? `app.use(passport.session());`. Or am I missing something? I can sign users up and log them in, so I know that my passport sessions are working properly. – Wesley Porter Sep 02 '14 at 17:01
  • Is there any way to attach user username to the socket as well? – Michael Kurowski Apr 06 '18 at 21:58
-1

The passport.socketio package works with previous version of socket.io. At least this code works with socket.io v0.9.17 - https://github.com/vodolaz095/hunt/blob/v_0_2_x/lib/http/socket.io.js

vodolaz095
  • 6,680
  • 4
  • 27
  • 42
  • As these technologies are being updated regularly, I want to use the most up-to-date packages. I also attempted to downgrade to 0.9.17, but it didn't work with my code (I changed the io.use to io.set and added the parameter 'authorization'). The link does not provide a solution to the problem. – Wesley Porter Aug 25 '14 at 16:23
-1

Ther is my full code: express, mongoDB session store, socket.io, passport-local, passport.socketio:

package.json

{
  "name": "application-name",
  "version": "0.0.1",
  "devDependencies": {
    "body-parser": "^1.15.0",
    "connect-ensure-login": "^0.1.1",
    "connect-mongo": "^1.1.0",
    "cookie-parser": "^1.4.1",
    "express": "^4.13.4",
    "express-session": "^1.13.0",
    "mongoose": "^4.4.5",
    "passport": "^0.3.2",
    "passport-local": "^1.0.0",
    "passport.socketio": "^3.6.1",
    "socket.io": "^1.4.5"
  }
}

server.js

"use strict";

const COOKIE_SECRET = 'keyboard cat!?!';
const MONGO_CFG = { url: 'mongodb://localhost:27017/db', autoReconnect: true };

var path = require("path");
var Server = require("http").Server;
var express = require('express');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require("express-session");
var MongoStore = require("connect-mongo/es5")(session);

// ToDo: make control it by DB
var user = {id:1, username:'1!', perm: '1,2,3'};

var passport = require('passport');
var Strategy = require('passport-local').Strategy;
passport.use(new Strategy( function(username, password, cb) { return cb(null, user); }));
passport.serializeUser(function(user, cb) { cb(null, user.id); });
passport.deserializeUser(function(id, cb) { cb(null, user); });

var sessionStore = new MongoStore(MONGO_CFG);
var sessionMiddleware = session({
    resave: false, // true - всегда записывать сессию в хранилище, даже если ничего не изменилось
    unset: 'destroy', // Удалять сессию из БД при логауте
    saveUninitialized: false, // Не сохранять в стор новую и пока не изменившуюся запись
    store: sessionStore,
    secret: COOKIE_SECRET
});

var app = express();
var server = Server(app);

app.use(cookieParser(COOKIE_SECRET));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(sessionMiddleware);

app.use(passport.initialize());
app.use(passport.session());

app.get('/',
    function(req, res) {
        var html;
        if (req.user) {
            html = `<p>Hello, ${req.user.username}. View your <a href="/profile">profile</a>.</p>`;
        } else {
            html = '<p>Welcome! Please <a href="/login">log in</a>.</p>'
        }
        res.send(html + '<script src="/socket.io/socket.io.js"></script><script>var socket = io();</script>');
    });

app.get('/login',
    function(req, res){
        res.send(`
            <form action="/login" method="post">
                <div><label>Username:</label><input type="text" name="username"/><br/></div>
                <div><label>Password:</label><input type="password" name="password"/></div>
                <div><input type="submit" value="Submit"/></div>
            </form>`
        );
    });

app.post('/login',
    passport.authenticate('local', { failureRedirect: '/login' }),
    function(req, res) {
        res.redirect('/');
    });

app.get('/logout',
    function(req, res){
        req.logout();
        res.redirect('/');
    });

app.get('/profile',
    require('connect-ensure-login').ensureLoggedIn(),
    function(req, res){
        res.send(`<p>ID: ${req.user.id}<br/>Username: ${req.user.username}</p><a href="/logout">Log out</a>`);
    });

server.listen(3000);

var io = require("socket.io")(server);
var passportSocketIo = require("passport.socketio");

io.use(passportSocketIo.authorize({
    cookieParser: cookieParser,
    secret:       COOKIE_SECRET,
    store:        sessionStore,
    success:      onAuthorizeSuccess,
    fail:         onAuthorizeFail
}));

function onAuthorizeSuccess(data, accept){
    console.log('successful connection to socket.io');
    accept();
}

function onAuthorizeFail(data, message, error, accept){
    if(error)
        throw new Error(message);
    console.log('failed connection to socket.io:', message);
    return accept(new Error(message));
}
John Hascall
  • 9,176
  • 6
  • 48
  • 72
MiF
  • 638
  • 7
  • 13