I am using passport to authenticate a user. My node.js server is working as a proxy server for another server; I can send an authenticate request to the other server to verify that the user and the password are correct.
I am having trouble with the function I need to include inside my deserializeUser, because the other server doesn't include any way to search for a given user by id.
First, here are my serialize and deserialize functions. Note that I am using the username as my identifier.
passport.serializeUser(function(user, done) {
done(null, user.username);
});
//used to deserialize the user from the session
passport.deserializeUser(function(username, done) {
user.findByUsername(username, function(err, user) {
done(err, user);
});
});
For the local strategy, here is my code:
passport.use('local-login', new LocalStrategy({
//use the fields for username and password
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true
},
function(req, username, password, done) {
var loginUser = new User('username', 'password');
loginUser.authenticate(function(err, user) {
if(!user)
return done(null, false, req.flash('loginMessage', 'No user found.'));
return done(null, user);
}));
the authenticate function is defined as follows(pseudocode included for brevity):
function(callback) {
//make a call to the external server with this.username and this.password as credentials
//if error
callback(err, null)
//if the external server verifies the call,
callback(null, user)
}
What should I use in my deserializeUser?
Also, I don't even understand why deserializeUser needs a user object. Isn't it just extracting the user from the session? Or is that a fundamental misunderstanding on my part?
The deserializeUser
function takes the user identifier (which is stored in the session), and uses it to get your full user object from your user store, in order to populate the user member of your express request object.
This is useful because you probably don't want to store your full user object in the session, just a reference to it, and then you can go get the full object from your database or other user store on each request.
Using a username for the identifier in serializeUser
and deserializeUser
seems like it should work, as long as the identifier is consistent between the two.
As far as serializing the user object out of your separate store -- the contents of that user object are mostly for your convenience. If you have code in some of your routes that will want to check some property of the user, this is the place to put it. If your code doesn't need to know anything other than that it's a valid user, your user object can just be {username: username}
.
--
So, in your example you mention that your external server is only able to validate that usernames and passwords are correct, and gives you a token back. If you have no other separate store of information about the users, that means that the only information your app will want to retain about the user is that they have authenticated and what their username and token are.
Then your local strategy would look something like:
passport.use('local-login', new LocalStrategy({
//use the fields for username and password
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true
},
function(req, username, password, done) {
somehowAuthenticateWithMyExternalServer(username, password, function(isValid, token) {
if(!isValid)
return done(null, false, req.flash('loginMessage', 'No user found.'));
return done(null, { username: username, token: token });
});
}));
Since you want to just keep this user object in the session instead of serializing it off anywhere, your serialize/deserialize functions can just be trivial pass-throughs:
passport.serializeUser(function(user, done) {
done(null, user);
});
//used to deserialize the user from the session
passport.deserializeUser(function(user, done) {
done(null, user);
});
(maybe it is possible to omit these all together in this case, not sure)
Then if any of your routes examine at the req.user
object, its only properties will be username
and 'token.