Skip to content
access passport.js authenticated user information from socket.io connection
Branch: master
Clone or download
Latest commit 0aea29d Oct 31, 2016
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
lib
test update documentation and tests to express 4. closes #63 Mar 23, 2015
.gitignore initial Sep 5, 2012
.travis.yml
README.md
package.json 3.7.0 Oct 31, 2016

README.md

Build Status

passport.socketio

Access passport.js user information from a socket.io connection.

Installation

npm install passport.socketio

Example usage

// initialize our modules
var io               = require("socket.io")(server),
    sessionStore     = require('awesomeSessionStore'), // find a working session store (have a look at the readme)
    passportSocketIo = require("passport.socketio");

// With Socket.io < 1.0
io.set('authorization', passportSocketIo.authorize({
  cookieParser: express.cookieParser,
  key:         'express.sid',       // the name of the cookie where express/connect stores its session_id
  secret:      'session_secret',    // the session_secret to parse the cookie
  store:       sessionStore,        // we NEED to use a sessionstore. no memorystore please
  success:     onAuthorizeSuccess,  // *optional* callback on success - read more below
  fail:        onAuthorizeFail,     // *optional* callback on fail/error - read more below
}));

//With Socket.io >= 1.0
io.use(passportSocketIo.authorize({
  cookieParser: cookieParser,       // the same middleware you registrer in express
  key:          'express.sid',       // the name of the cookie where express/connect stores its session_id
  secret:       'session_secret',    // the session_secret to parse the cookie
  store:        sessionStore,        // we NEED to use a sessionstore. no memorystore please
  success:      onAuthorizeSuccess,  // *optional* callback on success - read more below
  fail:         onAuthorizeFail,     // *optional* callback on fail/error - read more below
}));

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

  // The accept-callback still allows us to decide whether to
  // accept the connection or not.
  accept(null, true);

  // OR

  // If you use socket.io@1.X the callback looks different
  accept();
}

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

  // We use this callback to log all of our failed connections.
  accept(null, false);

  // OR

  // If you use socket.io@1.X the callback looks different
  // If you don't want to accept the connection
  if(error)
    accept(new Error(message));
  // this error will be sent to the user as a special error-package
  // see: http://socket.io/docs/client-api/#socket > error-object
}

passport.socketio - Options

store [function] required:

Always provide one. If you don't know what sessionStore to use, have a look at this list. Also be sure to use the same sessionStore or at least a connection to the same collection/table/whatever. And don't forget your express.session() middleware: app.use(express.session({ store: awesomeSessionStore })); For further info about this middleware see the official documentation.

You can also check the simple example below using a redis store.

//in your app.js
var sessionStore = new redisStore();

app.use(session({
  key: 'express.sid',
  store: sessionStore,
  secret: 'keyboard cat'
}));

//in your passport.socketio setup
//With Socket.io >= 1.0 (you will have the same setup for Socket.io <1)
io.use(passportSocketIo.authorize({
  cookieParser: require('cookie-parser'), //optional your cookie-parser middleware function. Defaults to require('cookie-parser')
  key:          'express.sid',       //make sure is the same as in your session settings in app.js
  secret:       'keyboard cat',      //make sure is the same as in your session settings in app.js
  store:        sessionStore,        //you need to use the same sessionStore you defined in the app.use(session({... in app.js
  success:      onAuthorizeSuccess,  // *optional* callback on success
  fail:         onAuthorizeFail,     // *optional* callback on fail/error
}));

cookieParser [function] optional:

Optional cookieParser from express. Express 3 is express.cookieParser in Express 4 require('cookie-parser').

Defaults to require('cookie-parser').

key [string] optional:

Defaults to 'connect.sid'. But you're always better of to be sure and set your own key. Don't forget to also change it in your express.session(): app.use(express.session({ key: 'your.sid-key' }));

secret [string] optional:

As with key, also the secret you provide is optional. But: be sure to have one. That's always safer. You can set it like the key: app.use(express.session({ secret: 'pinkie ate my cupcakes!' }));

passport [function] optional:

Defaults to require('passport'). If you want, you can provide your own instance of passport for whatever reason.

success [function] optional:

Callback which will be called everytime a authorized user successfuly connects to your socket.io instance. Always be sure to accept/reject the connection. For that, there are two parameters: function(data[object], accept[function]). data contains all the user-information from passport. The second parameter is for accepting/rejecting connections. Use it like this if you use socket.io under 1.0:

// accept connection
accept(null, true);

// reject connection (for whatever reason)
accept(null, false);

And like this if you use the newest version of socket.io@1.X

// accept connection
accept();

// reject connection (for whatever reason)
accept(new Error('optional reason'));

fail [function] optional:

The name of this callback may be a little confusing. While it is called when a not-authorized-user connects, it is also called when there's a error. For debugging reasons you are provided with two additional parameters function(data[object], message[string], error[bool], accept[function]): (socket.io @ < 1.X)

/* ... */
function onAuthorizeFail(data, message, error, accept){
  // error indicates whether the fail is due to an error or just a unauthorized client
  if(error){
    throw new Error(message);
  } else {
    console.log(message);
    // the same accept-method as above in the success-callback
    accept(null, false);
  }
}

// or
// This function accepts every client unless there's an error
function onAuthorizeFail(data, message, error, accept){
  console.log(message);
  accept(null, !error);
}

Socket.io@1.X:

function onAuthorizeFail(data, message, error, accept){
  // error indicates whether the fail is due to an error or just a unauthorized client
  if(error)  throw new Error(message);
  // send the (not-fatal) error-message to the client and deny the connection
  return accept(new Error(message));
}

// or
// This function accepts every client unless there's an critical error
function onAuthorizeFail(data, message, error, accept){
  if(error)  throw new Error(message);
  return accept();
}

You can use the message parameter for debugging/logging/etc uses.

socket.handshake.user (prior to v1)

This property was removed in v1. See socket.request.user

socket.request.user (as of v1)

This property is always available from inside a io.on('connection') handler. If the user is authorized via passport, you can access all the properties from there. Plus you have the socket.request.user.logged_in property which tells you whether the user is currently authorized or not.

Note: This property was named socket.handshake.user prior to v1

Additional methods

passportSocketIo.filterSocketsByUser

This function gives you the ability to filter all connected sockets via a user property. Needs two parameters function(io, function(user)). Example:

passportSocketIo.filterSocketsByUser(io, function(user){
  return user.gender === 'female';
}).forEach(function(socket){
  socket.emit('messsage', 'hello, woman!');
});

CORS-Workaround:

If you happen to have to work with Cross-Origin-Requests (marked by socket.io v0.9 as handshake.xdomain and by socket.io v1.0 as request.xdomain) then here's a workaround:

Clientside:

You have to provide the session-cookie. If you haven't set a name yet, do it like this: app.use(express.session({ key: 'your.sid-key' }));

// Note: ther's no readCookie-function built in.
// Get your own in the internetz
socket = io.connect('//' + window.location.host, {
  query: 'session_id=' + readCookie('your.sid-key')
});

Serverside:

Nope, there's nothing to do on the server side. Just be sure that the cookies names match.

Notes:

  • Does NOT support cookie-based sessions. eg: express.cookieSession
  • If the connection fails, check if you are requesting from a client via CORS. Check socket.handshake.xdomain === true (socket.request.xdomain === true with socket.io v1) as there are no cookies sent. For a workaround look at the code above.

Contribute

You are always welcome to open an issue or provide a pull-request! Also check out the unit tests:

npm test

License

Licensed under the MIT-License. 2012-2013 José F. Romaniello.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.