For the past few days I have been developing my first User login & authentication system using Passport.js. Awkwardly enough, I have finished it and it works just as intended. The problem is, even though I have read a lot of articles and checked tens of examples online, I seem to not completely understand the code per se. I have no issues understanding the process behind it and why it has to happen like that. I would really appreciate it if you could clarify some parts of the code for me. This is the working code, stored in my app.js file:
// Passport session setup
passport.serializeUser(function (user, done) {
done(null, user._id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// Use the Local Strategy within passport
passport.use(new LocalStrategy(function (username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, { message: 'Unknown user: ' + username});
}
user.comparePassword(password, function(err, isMatch) {
if (err) {
return done(err);
}
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Invalid Password' });
}
});
});
}));
var app = module.exports = express();
app.configure(function () {
app.set('views', path.join(__dirname + '/views'));
app.set('view engine', 'html');
app.engine('html', hbs.__express);
app.use(express.logger());
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.session({ secret: 'xxx' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(path.join(__dirname + '/public')));
});
I am using MongoDB (User - mongoose model). Also, to store passwords in the database I am currently using bcrypt.
I think that the most critical part that I do not understand here is the done callback function. I can understand that it simply passes some values, and I know that much to realize that the first parameter of it is the error and the second the data. Still, I do not fully grasp it because I haven't specifically provided one as a parameter. For example, if I would have a function like this:
// Random Function
var randomFunction = function (a, b, done) {
done(a, b);
};
// Then I would call the randomFunction providing my own **done**
randomFunction('Random', 'Words', function(a, b) { return a + b; });
Still, in my example I am not the one specifying the done callback. Is it simply a required callback function parameter or is it the same as the next function in a normal middleware such as:
function middleware (req, res, next) {
next(req.user); // pass the req.user to next middleware
}
Also, where does Passport.js bind the user that it handles? Does it bind it to req.user? And how can I pass it to certain views in order, for example, to display the username?
I am looking forward to your feedback!
Thank you!
Passport exposes a login() function on req (also aliased as logIn() ) that can be used to establish a login session. req.
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.
Done callback
Look at the code of Local Strategy:
function Strategy(options, verify) {
...
this._verify = verify;
...
}
verify
is the function that will be used by strategy to verify a user and you've specified it here:
passport.use(new LocalStrategy(function (username, password, done) {
// your verification code here
}));
Later in strategy you can find authenticate method that calls verify function from the step above:
this._verify(username, password, verified);
So, you now see where username
, password
and done==verified
come from. Later in your code you will call the done
callback with (err, user, info) arguments. In a few words, done
is needed to finish asynchronous procedure of user verification.
req.user and views
Yes, you are right about req.user
. So you can pass it to your views by two ways:
As an argument of res.render
function. See docs
res.render('some-template', { name: req.user });
Use res.locals
as some kind of context provider (now user object will be available in all the views that are defined in app.router
). See docs
// before app.use(app.router);
app.use(function(req, res, next) {
res.locals.user = req.user;
next();
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With