Validate PassportJS via Callback or Mongoose Model? - node.js

I am setting up passport for the sign up and login user authentication. Now I saw that I can validate the information via the callback, however I could also validate the information in the User model. For example, if I want to make the email field required, then I can do the following:
Validation with Passport
// Create the local sign up with Passport
passport.use('local-signup', new LocalStrategy({
usernameField : 'userEmail', // Email Field
passwordField : 'userPassword', // Password Field
passReqToCallback : true
},
function(req, email, password, done) {
// Find a user with this email
User.findOne({ "local.email": email }, function(err, user) {
if (err) throw err;
// If a user with this email already exists, continue with failureRedirect
if (user) {
return done(null);
} else {
// Otherwise create a new user with the email and generate a hashed password
User.create({
local: {
email: email
}
}, function(err, user) {
if (err) throw err;
user.local.password = user.generateHash(password);
// Return the user and finish! :)
return done(null, user);
});
}
});
};
}));
With the User Model
var userSchema = new Schema({
local: {
email: {
type: String,
unique: true // Make it unique! Handles entire validation
},
password: {
type: String
},
}
});
Which of them is recommended and why?

Why not both? If you use the second one only, it will be difficult to show the message
email address already exists
as you need to catch the duplicate key error index and then display the error message at signup. Instead of that you could check that if email address already exists which is more explicit and display the corresponding error message at signup at the same time using unique index will make sure that there are no duplicate entries for email address.

Related

Passport JS Google oauth20 callback missing req object

I have seen some similar questions here but the answer is irrelevant to mine, as I have declared passReqToCallback.
I am trying to create an authentication system with passport. I have successfully integrated passport-local, which register/logs in user and creates a session but am having an issue in the logic of the google strategy:
passport.use(new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.GOOGLE_CALLBACK_URL,
passReqToCallback: true
},
(req, accessToken, refreshToken, profile, done) => {
/**
*
* This if statement is failing, as far as I can tell there is no req object being passed despite declaring it above
*
*/
// If user is logged in, proceed to simply link account
if (req.user) {
req.user.googleid = profile.id;
req.user.googleEmail = profile.emails[0].value;
req.user.googleDisplayName = profile.displayname;
pool.query('UPDATE users SET googleid = ?, google_email = ?, google_display_name = ? WHERE id = ?', [
req.user.googleid,
req.user.googleEmail,
req.user.googleDisplayName,
req.id
],
function(err, rows) {
// If google account is duplicate (linked to different account) will return error
if (err) {
return done(err, false, {message: "The Google account you tried to link is associated with another account."});
}
return done(null, req.user);
})
}
// Check if google account is registered
pool.query('SELECT * FROM users WHERE googleid = ?', [profile.id], function(err, rows) {
if (err) {
return done(err);
}
// If not logged in but user already registered, log in
if (rows.length) {
return done(null, rows[0]);
}
// If no existing record, register the user.
else {
let newUser = {
email: profile.emails[0].value,
// Google account specific fields
googleid: profile.id,
googleDisplayName: profile.displayName,
method: "gl", // This field ties this new user to the google account
// General fields (taken from the stuff google gives us)
firstName: profile.name.givenName,
lastName: profile.name.familyName,
googleEmail: profile.emails[0].value
}
let insertQuery = "INSERT INTO users (email, googleid, google_display_name, method, first_name, last_name, google_email) VALUES (?,?,?,?,?,?,?)";
pool.query(insertQuery, [
newUser.email,
newUser.googleid,
newUser.googleDisplayName,
newUser.method,
newUser.firstName,
newUser.lastName,
newUser.googleEmail
],
function(err, rows) {
if (err) return done(err, null);
newUser.id = rows.insertId;
return done(null, newUser);
})
}
})}));
So essentially the first if is supposed to see if the user is already authenticated and then just link the account as so. However, in practice, it will skip this even when authenticated and proceed to the rest of the logic, which works absolutely fine. It will go on to create a new account at the else statement (or return error if email is taken, I still need to implement that part).
But, interestingly, if I am logged in while using it, it doesn't log me in as the new user as it otherwise would, instead it keeps me logged in as the current session.
Where have I gone wrong? Why is the req.user not detected? I have also tried using req.isAuthenticated() with the same result.
Below is my callback route, if helpful:
// Google
router.get('/oauth/google', passport.authenticate('google', {
scope: ['email', 'profile']
}));
// Callback
router.get('/oauth/google/redirect', passport.authenticate('google', {
successRedirect: '/account',
failureFlash: 'Something went wrong. Please enable third party cookies to allow Google to sign in.',
failureRedirect: '/login'
}
));
UPDATE 1: If I try (!req.user), same result, skips to below, not sure what that means is happening

How to confirm email address using express/node?

I'm trying to build verification of email address for users, to verify their email is real. What package should I use to confirm the email address of the user? So far Im using mongoose and express
Code Example
var UserSchema = new mongoose.Schema({
email: { type: String, unique: true, lowercase: true }
password: String
});
var User = mongoose.model('User', UserSchema);
app.post('/signup', function(req, res, next) {
// Create a new User
var user = new User();
user.email = req.body.email;
user.password = req.body.password;
user.save();
});
In the app.post codes, how do i confirm the email address of the user?
What you're looking for is called "account verification" or "email verification". There are plenty of Node modules that can perform this, but the principle goes like this:
Your User model should have an active attribute that is false by default
When the user submits a valid signup form, create a new User (who's active will be false initially)
Create a long random string (128 characters is usually good) with a crypto library and store it in your database with a reference to the User ID
Send an email to the supplied email address with the hash as part of a link pointing back to a route on your server
When a user clicks the link and hits your route, check for the hash passed in the URL
If the hash exists in the database, get the related user and set their active property to true
Delete the hash from the database, it is no longer needed
Your user is now verified.
var express=require('express');
var nodemailer = require("nodemailer");
var app=express();
/*
Here we are configuring our SMTP Server details.
STMP is mail server which is responsible for sending and recieving email.
*/
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "Your Gmail ID",
pass: "Gmail Password"
}
});
var rand,mailOptions,host,link;
/*------------------SMTP Over-----------------------------*/
/*------------------Routing Started ------------------------*/
app.get('/',function(req,res){
res.sendfile('index.html');
});
app.get('/send',function(req,res){
rand=Math.floor((Math.random() * 100) + 54);
host=req.get('host');
link="http://"+req.get('host')+"/verify?id="+rand;
mailOptions={
to : req.query.to,
subject : "Please confirm your Email account",
html : "Hello,<br> Please Click on the link to verify your email.<br>Click here to verify"
}
console.log(mailOptions);
smtpTransport.sendMail(mailOptions, function(error, response){
if(error){
console.log(error);
res.end("error");
}else{
console.log("Message sent: " + response.message);
res.end("sent");
}
});
});
app.get('/verify',function(req,res){
console.log(req.protocol+":/"+req.get('host'));
if((req.protocol+"://"+req.get('host'))==("http://"+host))
{
console.log("Domain is matched. Information is from Authentic email");
if(req.query.id==rand)
{
console.log("email is verified");
res.end("<h1>Email "+mailOptions.to+" is been Successfully verified");
}
else
{
console.log("email is not verified");
res.end("<h1>Bad Request</h1>");
}
}
else
{
res.end("<h1>Request is from unknown source");
}
});
/*--------------------Routing Over----------------------------*/
app.listen(3000,function(){
console.log("Express Started on Port 3000");
});
Follow the code example, you can use nodemailer to send the link, and then verify it.
Here is a link: https://codeforgeek.com/2014/07/node-email-verification-script/
Step 1:
User Model
var userSchema = new mongoose.Schema({
email: { type: String, unique: true },
isVerified: { type: Boolean, default: false },
password: String,
});
Token Model
const tokenSchema = new mongoose.Schema({
_userId: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'User' },
token: { type: String, required: true },
expireAt: { type: Date, default: Date.now, index: { expires: 86400000 } }
});
Step 2: Login
exports.login = function(req, res, next) {
User.findOne({ email: req.body.email }, function(err, user) {
// error occur
if(err){
return res.status(500).send({msg: err.message});
}
// user is not found in database i.e. user is not registered yet.
else if (!user){
return res.status(401).send({ msg:'The email address ' + req.body.email + ' is not associated with any account. please check and try again!'});
}
// comapre user's password if user is find in above step
else if(!Bcrypt.compareSync(req.body.password, user.password)){
return res.status(401).send({msg:'Wrong Password!'});
}
// check user is verified or not
else if (!user.isVerified){
return res.status(401).send({msg:'Your Email has not been verified. Please click on resend'});
}
// user successfully logged in
else{
return res.status(200).send('User successfully logged in.');
}
});
});
Step 3: Sign Up
exports.signup = function(req, res, next) {
User.findOne({ email: req.body.email }, function (err, user) {
// error occur
if(err){
return res.status(500).send({msg: err.message});
}
// if email is exist into database i.e. email is associated with another user.
else if (user) {
return res.status(400).send({msg:'This email address is already associated with another account.'});
}
// if user is not exist into database then save the user into database for register account
else{
// password hashing for save into databse
req.body.password = Bcrypt.hashSync(req.body.password, 10);
// create and save user
user = new User({ name: req.body.name, email: req.body.email, password: req.body.password });
user.save(function (err) {
if (err) {
return res.status(500).send({msg:err.message});
}
// generate token and save
var token = new Token({ _userId: user._id, token: crypto.randomBytes(16).toString('hex') });
token.save(function (err) {
if(err){
return res.status(500).send({msg:err.message});
}
// Send email (use credintials of SendGrid)
var transporter = nodemailer.createTransport({ service: 'Sendgrid', auth: { user: process.env.SENDGRID_USERNAME, pass: process.env.SENDGRID_PASSWORD } });
var mailOptions = { from: 'no-reply#example.com', to: user.email, subject: 'Account Verification Link', text: 'Hello '+ req.body.name +',\n\n' + 'Please verify your account by clicking the link: \nhttp:\/\/' + req.headers.host + '\/confirmation\/' + user.email + '\/' + token.token + '\n\nThank You!\n' };
transporter.sendMail(mailOptions, function (err) {
if (err) {
return res.status(500).send({msg:'Technical Issue!, Please click on resend for verify your Email.'});
}
return res.status(200).send('A verification email has been sent to ' + user.email + '. It will be expire after one day. If you not get verification Email click on resend token.');
});
});
});
}
});
});
Step 4: Verify Account
// It is GET method, you have to write like that
// app.get('/confirmation/:email/:token',confirmEmail)
exports.confirmEmail = function (req, res, next) {
Token.findOne({ token: req.params.token }, function (err, token) {
// token is not found into database i.e. token may have expired
if (!token){
return res.status(400).send({msg:'Your verification link may have expired. Please click on resend for verify your Email.'});
}
// if token is found then check valid user
else{
User.findOne({ _id: token._userId, email: req.params.email }, function (err, user) {
// not valid user
if (!user){
return res.status(401).send({msg:'We were unable to find a user for this verification. Please SignUp!'});
}
// user is already verified
else if (user.isVerified){
return res.status(200).send('User has been already verified. Please Login');
}
// verify user
else{
// change isVerified to true
user.isVerified = true;
user.save(function (err) {
// error occur
if(err){
return res.status(500).send({msg: err.message});
}
// account successfully verified
else{
return res.status(200).send('Your account has been successfully verified');
}
});
}
});
}
});
});
Step 5: Resend Link
exports.resendLink = function (req, res, next) {
User.findOne({ email: req.body.email }, function (err, user) {
// user is not found into database
if (!user){
return res.status(400).send({msg:'We were unable to find a user with that email. Make sure your Email is correct!'});
}
// user has been already verified
else if (user.isVerified){
return res.status(200).send('This account has been already verified. Please log in.');
}
// send verification link
else{
// generate token and save
var token = new Token({ _userId: user._id, token: crypto.randomBytes(16).toString('hex') });
token.save(function (err) {
if (err) {
return res.status(500).send({msg:err.message});
}
// Send email (use credintials of SendGrid)
var transporter = nodemailer.createTransport({ service: 'Sendgrid', auth: { user: process.env.SENDGRID_USERNAME, pass: process.env.SENDGRID_PASSWORD } });
var mailOptions = { from: 'no-reply#example.com', to: user.email, subject: 'Account Verification Link', text: 'Hello '+ user.name +',\n\n' + 'Please verify your account by clicking the link: \nhttp:\/\/' + req.headers.host + '\/confirmation\/' + user.email + '\/' + token.token + '\n\nThank You!\n' };
transporter.sendMail(mailOptions, function (err) {
if (err) {
return res.status(500).send({msg:'Technical Issue!, Please click on resend for verify your Email.'});
}
return res.status(200).send('A verification email has been sent to ' + user.email + '. It will be expire after one day. If you not get verification Email click on resend token.');
});
});
}
});
});
You can take help from this link:https://medium.com/#slgupta022/email-verification-using-sendgrid-in-node-js-express-js-mongodb-c5803f643e09
I would like to present a slightly different approach from the ones proposed.
This method does not put the hash into the database (therefore less interaction with it)
You don't need to register the hash in the database. Here's an overview after receiving a registration request:
You encode the user id + registration time
You send the token to the user
When the user triggers his registration request, you decode the token.
Because The decoded token contains the user id + the time, you can
mark the user as registered by increasing their role
(registered, subscriber, admin, etc.) for instance
Translated into code, you would have something like this:
1- Encode the token
function encodeRegistrationToken()
{
// jsonweb automatically adds a key that determines the time, but you can use any module
const jwt = require('jsonwebtoken');
// The information we need to find our user in the database (not sensible info)
let info = {id: yourUserId};
// The hash we will be sending to the user
const token = jwt.sign(info, "yoursecretkey");
return token;
}
// ...
let token = encodeRegistrationToken();
2- Send token to the user via any appropriate way
// Your implementation of sending the token
sendTokenToUser(token);
3- Decode the token
function decodeRegistrationToken(token)
{
const jwt = require('jsonwebtoken');
let decoded = jwt.verify(token, "yoursecretkey");
let userId = decoded.id;
// Check that the user didn't take too long
let dateNow = new Date();
let tokenTime = decoded.iat * 1000;
// Two hours
let hours = 2;
let tokenLife = hours * 60 * 1000;
// User took too long to enter the code
if (tokenTime + tokenLife < dateNow.getTime())
{
return {
expired: true
};
}
// User registered in time
return {
userID
};
}
4 - Update your database
Upgrade the user role to subscriber
or
Set their "register" key to true
Quick note: You can further encode the user id when encoding your token if you want (it's easily accessible).
I spent a lot of time figuring out the perfect way to send confirmation mail. Here is the method I used.
Libraries
const jwt = require('jsonwebtoken');
const nodemailer = require("nodemailer");
Step 1
Encode the user id in a jwt token with an expiration date
var date = new Date();
var mail = {
"id": user.id,
"created": date.toString()
}
const token_mail_verification = jwt.sign(mail, config.jwt_secret_mail, { expiresIn: '1d' });
var url = config.baseUrl + "verify?id=" + token_mail_verification;
Step 2
Send the token to the user email address using nodemailer library
let transporter = nodemailer.createTransport({
name: "www.domain.com",
host: "smtp.domain.com",
port: 323,
secure: false, // use SSL
auth: {
user: "user#domain.com", // username for your mail server
pass: "Password", // password
},
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: '"NAME" <user#domain.com>', // sender address
to: user.email, // list of receivers seperated by comma
subject: "Account Verification", // Subject line
text: "Click on the link below to veriy your account " + url, // plain text body
}, (error, info) => {
if (error) {
console.log(error)
return;
}
console.log('Message sent successfully!');
console.log(info);
transporter.close();
});
Step 3
Accept the verification link
app.get('/verify', function(req, res) {
token = req.query.id;
if (token) {
try {
jwt.verify(token, config.jwt_secret_mail, (e, decoded) => {
if (e) {
console.log(e)
return res.sendStatus(403)
} else {
id = decoded.id;
//Update your database here with whatever the verification flag you are using
}
});
} catch (err) {
console.log(err)
return res.sendStatus(403)
}
} else {
return res.sendStatus(403)
}
})
Step 4
Have a coffee and THANK ME for saving your so much time
PS: This nodemailer SMTP method will even work with your hosting. So no need to go for third party. You can also find ways to use gmail with nodemailer.
if you are just testing on your local machine, one simple way of understanding how to do it can be :
Assuming you already know sending mails through nodemailer..
Once user signs up, after storing sign-up data in your database, on your server side take user email from sign-up data received and a random generated number and build a custom url with the address of page where user will be directed after he/she clicks on the link given in mail.
var customUrl = "http://"+ your host + "/" + your verification web-page + "?email=" + userEmail + "&id=" + randomNumber;
An example can be:
var userEmail = someone#example.com
var host = localhost:8080
var directWebPage = verifyUserEmail.html
var randomNumber = // generate with math.random() // lets say 111
Putting in above format of customUrl it looks something like this
customUrl:http://localhost:8080/verifyUserEmail.htmlemail=someone#example.com&id=111
Save this customUrl somewhere (probably in your database)
Now, send an email to user with email body containing this cutomUrl link.
Click to verify your email
When user clicks on the link he/she will be directed to verifyUserEmail.html page and when that happens you can extract the page url containing email and id information
For example in angular I go like this-
var urlVerifyData = $location.url(); or $location.absUrl();
Now extract email form urlVerifyData string using javascript string methods
Request your server with this email and urlVerifyData
Now query your database for this email and verify previously stored customUrl with user's urlVerifyData
If they match, hola ! You got yourself a genuine user !!!
I came across a Reddit post where one explained that one click on the link is not sufficient and might lead to errors and a failure of the verification. The logic is simple and legit, when the email containing the link is received, there might be link scanners (bots) on the SMTP server (Outlook, Gmail etc). Just like when you past a link on major social platforms, there is always a bot that hits the link. I did not try it myself but I believe Outlook scans some links (when you copy past a link it is converted to a thumbnail with page's content).
So this process oblige you to do a verification by two steps, maybe when the user clicks, he needs to past his own password used for signup (looks fine). Or provide a one time password with the email so that the user along with the verification link (maybe split then re-concat) the same token you send for verification and ask the user to enter that second part (this seems easier).
function generateLink() {
var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
var token = '';
for (var i = 16; i > 0; --i) {
var rand = Math.round(Math.random() * (chars.length - 1))
token += chars[rand];
}
var link = "http://localhost" + "/verify?id=" + token;
return link;
}
// npm install #sendGrid/mail --save
//library for generating link using SendGrid
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey("SENDGRID_API_KEY"); //create an account on sendgrid and get an API key
// generated link is send to the user's email for email verification
let sendVerifyEmailLink = (req, res) => {
var link = generateLink();
const msg = {
to: 'test#gmail.com',
from: 'test#gmail.com',
subject: 'Account Verifictaion',
text: 'Hello,\n\n' + 'Please verify your account by clicking the link:\/\/\n',
html: 'Hello,\n\n <br> Please verify your account by clicking the link: \n <br> <strong><a href = ' + link + '>http:\/\/ Click here to verify the given Link </a></strong>.\n .<br>Thanks<br>',
};
sgMail.send(msg).then(() => { }, error => {
console.error(error);
if (error.response) {
console.error(error.response.body)
}
});
console.log(msg)
}

Passport-ldapauth fails to execute verify callback

Please , I have setup passport ldapauth which works fine with all parameters, the problem is if the username or password is wrong, the it does not execute further to the verify callback function at all. It just stops. Due to this I cannot give feedback to the users to indicate what is actually wrong. Is there any clue what I am missing?. This is the structure
passport.use('ldapStudent', new LdapStrategy({
usernameField: 'username',
passReqToCallback:true,
server: {
url: '..........',
bindDn: '.............',
bindCredentials: '..........',
searchBase: '..............',
searchFilter: '.............',
searchAttributes: ['givenName','sn'],
tlsOptions: {
ca: [fs.readFileSync('./ssl/server.crt', 'utf8')]
}
}
},
function (req, user, done) {
//now check from the DB if user exist
if(user){
//check if user email exist;
User.findOne({'EmailAddress': user}, function (err, userdata) {
// In case of any error, return using the done method
if (err)
return done(err);
//user exist redirect to home page and send user object to session
if (userdata) {
//userActivity(PostActivity);
console.log(userdata);
return done(null, userdata);
}else {
//new user, add them to the user model
var newUser = new User();
newUser.EmailAddress = req.body.username,
newUser.JoinedDate = Date.now(),
newUser.UserType = 'Student'
newUser.save(function (err, result) {
if (err) {
console.log('Error in Saving NewUser: ' + err);
} else {
console.log(result);
var PostActivity = {
ActivityName: req.res.__('Student Joined'),
ActivityDate: Date.now(),
UserID: result._id,
UserIP: (req.header('x-forwarded-for') || req.connection.remoteAddress ) + ' Port: ' + req.connection.remotePort
};
userActivity(PostActivity);
console.log('User Registration successful');
return done(null, newUser, req.flash('SuccessMessage', req.res.__('You have been successfully Registered')));
}
})
}
});
}else{
return done(null, false, req.flash('ValidationError', req.res.__('Wrong password and/or email address')));
}}));
This is where i actually do the login
router.post('/login', passport.authenticate('ldapStudent', {
successRedirect: '/',
failureRedirect: '/userlogin',
failureFlash: true
}));
The code works well , just as I expect, the parameters for the ldap option object are intentionally omitted.
The problem is when the user credential are not correct, the verify callback does not get executed at all and so, I can not return a flash message for the user to know what is happening
passport-ldapauth does not execute the verify callback if there is nothing to verify which is the case if the credentials are incorrect and the user is not received. This is in general how the strategies tend to work, e.g. passport-local does not execute verify callback if the username or password is missing.
Strategies, passport-ldapauth included, also usually include a (configurable) message for the failure flash. General configurable login failure messages for passport-ldapauth are listed in the documentation. Each of the messages also has a default value so even when not configured the failure flash message is set (given of course that you have flash middleware in use)
Also, you are not supposed to use req.flash() in the callback of the verify function but to supply an info message.

Authenticate user with passport through LinkedIn login

I have built a login system in Passport and works quite well. Now, I want to integrate LinkedIn login in my system. I already have clientID, clientSecret etc. needed to login. This is the code that is called when the LinkedIn login button is pressed.
passport.use('linkedin', new OAuth2Strategy({
authorizationURL: 'https://www.linkedin.com/uas/oauth2/authorization',
tokenURL: 'https://www.linkedin.com/uas/oauth2/accessToken',
clientID: clientid,
clientSecret: clientsecret,
callbackURL: '/linkedinLogin/linkedinCallbackUrlLogin',
passReqToCallback: true
},
function(req,accessToken, refreshToken, profile, done) {
console.log('authenticated');
console.log(accessToken);
req.session.code = accessToken;
process.nextTick(function () {
done(null, {
code : req.code
});
});
}));
Both the console.log() calls in the callback function are successfully fired, this means I am successfully logged in through LinkedIn and I receive my access token. The part where I connect with LinkedIn is thus correct, what I am missing is the part where I actually log in the user. As you can see, the callbackURL points to /linkedinLogin/linkedinCallbackUrlLogin. This is what I do in that route:
app.get('/linkedinLogin/linkedinCallbackUrlLogin', passport.authenticate('linkedin', {
session: false,
successRedirect:'/linkedinLogin/success',
failureRedirect:'/linkedinLogin/fail'
}));
I just specify a successRedirect and a failureRedirect. Note that if I put session : true I receive as an error Failed to serialize user into session, so for now I keep it to false.
The successRedirect is successfully called. In that route I call a GET request to LinkedIn to access some data about the user. I want to store this data in my DB and remember the user that logged in. This is how I do it:
https.get(
{
host: 'api.linkedin.com' ,
path: '/v1/people/~?format=json' ,
port:443 ,
headers : {'Authorization': ' Bearer ' + req.session.code}
},
function(myres) {
myres.on("data", function(chunk) {
var linkedinJsonResult = JSON.parse(chunk);
User.findOne({linkedinLogin : linkedinJsonResult.id}, function(err, userSearchResult){
if(err) {
throw err;
}
//user found, login
if(userSearchResult){
console.log(userSearchResult);
}
else {
//create user
var newUser = new User(
{
url : linkedinJsonResult.siteStandardProfileRequest.url,
name : linkedinJsonResult.firstName + " " + linkedinJsonResult.lastName,
linkedinLogin : linkedinJsonResult.id,
regDate : new Date()
}
);
//save user
newUser.save(function(err, user){
if(err){
throw err;
}
//login
console.log(user);
});
}
});
});
}
);
Let me explain the code there. After getting the data of the user I check the field "id" that is received. If this id matches one of my users' linkedinLogin field stored into the DB, I consider it already registered (the user has been found in the DB), thus I have to log him/her in. Otherwise I just create a new user using the data received from the GET request.
My question is, in both the cases - the user is found in my DB, or the user has to be created - how can I set req.user to be my user whenever it interacts with my website? Is it sufficient to just do req.user = userSearchResult (if the user is found, inside the if statement) or req.user = user (if the user has been created, inside the newUser.save() callback), or should I call some passport functions that will set it for me?
All the other passport functions related to the registration and login of users without using LinkedIn login are working fine. I am just worried about making this LinkedIn login work with passport.
Thank you.
passport.js will automatically set the req.user object to the object you will pass as the second argument to the done function of the strategy callback.
This means that you should do something like this:
function(req,accessToken, refreshToken, profile, done) {
console.log('authenticated');
console.log(accessToken);
req.session.code = accessToken;
process.nextTick(function () {
// retrieve your user here
getOrCreateUser(profile, function(err, user){
if(err) return done(err);
done(null, user);
})
});
}));
I hope this helps.

For Passport-Local with Node.js, is it possible to authenticate with email rather than username?

I'm using passport-local to provide local authentication on my node app. However, I would like to change this to authenticate with an email address rather than a username. Is there a way to do this?
Thank you.
You must first change the default username field to email with { usernameField: 'email' } you can then run a database search based on the email and check the password:
passport.use(new LocalStrategy({ usernameField: 'email' }, function(email, password, done) {
UserModel.findOne({ email: email }, function(err, user) {
// Check password functionality
})
})
Since you have to implement the validation yourself (in the LocalStrategy verifier callback), you can pass it anything you like:
passport.use(new LocalStrategy(function(email, password, done) {
// search your database, or whatever, for the e-mail address
// and check the password...
});
You can query the database for the email-id from request params like below:
passport.use('signup', new LocalStrategy({
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) {
//console.log(email);
console.log(req.param('email'));
findOrCreateUser = function(){
// find a user in Mongo with provided username
User.findOne({ 'email' : req.param('email') }, function(err, user) {
});
}))

Resources