Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to keep a user logged on? Is it possible with ExpressJS and Passport?

I have a server in node.js using express and passport with the passport-local strategy.

I have the users in the database and through passport I'm able to authenticate them, unfortunately when a second request comes from the same client the req.isAuthenticated() method returns false. There is also no user in the request (req.user = undefined).

I've also checked and when doing the authentication although I get back a user from passport.authenticate('local'... I do not get req.user populated then. If I try to set it up manually it just doesn't propagate for following requests.

I don't understand what I'm doing wrong, here is my code.

server.js

var express = require('express'),
compass = require('node-compass'),
routes = require('./server/routes')
http = require('http'),
path = require('path'),
passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
Database = require('./server/repositories/database'),
Configuration = require('./server/config').Config,
crypto = require('crypto');

var app = express();

app.enable("jsonp callback");

passport.use(new LocalStrategy(
  function(email, password, done) {
    process.nextTick(function () {
      var userService = new UserService();
      userService.login(email, crypto.createHash('md5').update(password).digest("hex"), function(error, user) {
        if (error) done(error, user);
        else if (!user) return done(null, false, { message: 'wrong credentials'}); 
        return done(null, user);
      });
    });
  }
));

passport.serializeUser(function(user, done) {
  done(null, user._id);
});

passport.deserializeUser(function(id, done) {
  var userService = new UserService();
  userService.findById(id, function(err, user) {
    done(err, user);
  });
});

app.configure(function(){
  app.set('port', Configuration.Port);
  app.set('views', __dirname + '/app/views');
  app.set('view engine', 'ejs');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.cookieParser()); 
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(compass({
    project: path.join(__dirname, 'app'),
      sass: 'styles'
  }));
  app.use(express.session({ secret: 'keyboard cat' }));
  app.use(function(err, req, res, next){
    console.error(err.stack);
    res.send(500, 'Something broke!');
  });
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(app.router);
  app.use(express.static(path.join(__dirname, 'app')));
});

routes.configure(app);

Database.open(function() { 
  app.listen(Configuration.Port, function() {
    console.log("Express server listening on port " + Configuration.Port);
  });
});

routes.js

var Configuration = require('./config').Config;
var ApiResult = require('../model/apiResult').ApiResult;
var ApiErrorResult = require('../model/apiErrorResult').ApiErrorResult;
var ApiReturnCodes = require('../model/apiReturnCodes').ApiReturnCodes;
var passport = require('passport');

var usersController = require('./controllers/usersController');

exports.configure = function(app) {
  function ensureAuthenticated(req, res, next) {
    console.log(req.isAuthenticated());
    if (req.isAuthenticated()) { return next(); }
    else {res.send(new ApiErrorResult(ApiReturnCodes.NOT_LOGGED_IN, null));}
  }

  app.post('/login', function(req, res, next) {
    passport.authenticate('local', function(err, user, info) {
      if (err || !user) { console.log(info); res.send(new ApiErrorResult(ApiReturnCodes.ENTITY_NOT_FOUND, null)); }
      // If this function gets called, authentication was successful.
      // `req.user` contains the authenticated user
      else res.send(new ApiResult(user));
    })(req,res,next);
  });

  app.get('/anotherLink', ensureAuthenticated, function(req, res, next) {
    res.json({Code:0});
  });
}

When I hit the link /anotherLink after being authenticated I get res.isAuthenticated() as false.

Also when I see the req.session after the ensureAuthenticated is called I get:

{ cookie: 
   { path: '/',
     _expires: null,
     originalMaxAge: null,
     httpOnly: true },
  passport: {} }

What am I missing for it to save the information that that user is authenticated? On the client side I'm using Angular only doing a simple get with the url without parameters.

If I forgot to put something here just tell me, I'll update it. Any help will be greatly appreciated. Thanks

like image 368
Carlos Avatar asked Sep 11 '13 16:09

Carlos


People also ask

Should I use passport js for authentication?

Passport is a popular, modular authentication middleware for Node. js applications. With it, authentication can be easily integrated into any Node- and Express-based app. The Passport library provides more than 500 authentication mechanisms, including OAuth, JWT, and simple username and password based authentication.

What does req login () do in passport?

This function is primarily used when users sign up, during which req. login() can be invoked to automatically log in the newly registered user.

How does passport js handle authorization?

Authorization is performed by calling passport. authorize() . If authorization is granted, the result provided by the strategy's verify callback will be assigned to req.account . The existing login session and req.


1 Answers

So I found out what was wrong with my code.

My passport.deserializeUser method used the method userService.findById

And that called the repository... like this:

userRepository.findUnique({"_id": id}, callback);

because the id was generated by MongoDB the correct call needs to be:

userRepository.findUnique({"_id": new ObjectID(id)}, callback);

I hope this saves some time to the next person with the same problem.

With this detail, this code should work nicely for everyone wanting to use the LocalStrategy on the Passport framework.

like image 197
Carlos Avatar answered Nov 04 '22 09:11

Carlos