I have read several articles explaining how the passport authentication flows and understood most of the concepts. However, there are still a couple of vague points to be explained so that I can wrap my head around Passport once and for all.
Let's see this simple example that implements user registration:
passport.js
passport.use(
'register',
new LocalStrategy(
{
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true,
session: false,
},
(req, username, password, done) => {
// TODO:Why is req.body.email is used and not req.body.username
// And how are these values passed to register in the first place?
console.log(username);
console.log(req.body.email);
try {
User.findOne({
where: {
[Op.or]: [
{
username,
},
{ email: req.body.email },
],
},
}).then(user => {
if (user != null) {
console.log('username or email already taken');
return done(null, false, {
message: 'username or email already taken',
});
}
/**
* on register the user’s password is hashed and salted with the encryption package bcrypt
*
*/
bcrypt.hash(password, BCRYPT_SALT_ROUNDS).then(hashedPassword => {
User.create({
username,
password: hashedPassword,
email: req.body.email,
}).then(user => {
console.log('user created');
return done(null, user);
});
});
});
} catch (err) {
//In case of an Error interacting with our database, we need to invoke done(err)
//Calling done will make the flow jump back into passport.authenticate.
//It's passed the error, user and additional info object (if defined).
return done(err);
}
},
),
);
registerUser.js:
app.post('/registerUser', (req, res, next) => {
//Calling done will make the flow jump back into passport.authenticate.
//It's passed the error, user and additional info object (if defined).
passport.authenticate('register', (err, user, info) => {
if (err) {
console.error(err);
}
if (info !== undefined) {
console.error(info.message);
res.status(403).send(info.message);
} else {
// eslint-disable-next-line no-unused-vars
req.logIn(user, error => {
console.log(user);
const data = {
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
username: user.username,
};
console.log(data);
User.findOne({
where: {
username: data.username,
},
}).then(user => {
console.log(user);
user
.update({
first_name: data.first_name,
last_name: data.last_name,
email: data.email,
})
.then(() => {
console.log('user created in db');
res.status(200).send({ message: 'user created' });
});
});
});
}
})(req, res, next);
});
Question 1: I do not see how the code inside LocalStrategy has access to the user information knowing that Passport.authenticate has been called in this manner:
app.post('/registerUser', (req, res, next) => {
passport.authenticate('register', (err, user, info) => {
So how does the code inside **regiser LocalStrategy ** accesses the username,email and password:
(req, username, password, done) => {
console.log(username);
console.log(req.body.email);
Question2: How come username inside LocalStrategy is called username directly (the same thing for password) and email is called by req.body.email?
console.log(username);
console.log(req.body.email);
and here:
User.create({
username,
password: hashedPassword,
email: req.body.email,
})
Question 3: Why is there a need to update the user information in the request callback if the user has already been created in the register LocalStrategy:
registerUser.js
.update({
first_name: data.first_name,
last_name: data.last_name,
email: data.email,
})
passport.js
User.create({
username,
password: hashedPassword,
email: req.body.email,
})
EDIT 1
Question 4: What is the role of (req, res, next); at the end of the POST callback?