passport js update req.user data when changing user data - javascript

I'm trying to update the data in my req.user when I change the user data like changing the email validation from false to true. What is the best way to do this? at the moment I run req.logIn again but this doesn't seem like a great solution.
So is there a way to update the user data in my req.user without running req.logIn again.
My Passport.js config:
//=============================================================================
// OAuth2.0 Setup Start
//=============================================================================
const passport = require('passport')
const bcrypt = require('bcryptjs')
const GoogleStrategy = require('passport-google-oauth20').Strategy
const LocalStrategy = require('passport-local').Strategy
const User = require('../models/User')
const userLimit = require('../routes/utils/userLimit')
passport.serializeUser(function (user, done) {
console.log('user: ', user)
done(null, user)
})
passport.deserializeUser(function (obj, done) {
done(null, obj)
})
//=============================================================================
// OAuth2.0 Google Start
//=============================================================================
passport.use(
new GoogleStrategy(
{
clientID: `${process.env.clientID}`,
clientSecret: `${process.env.clientSecret}`,
callbackURL: `${process.env.url}/auth/google/callback`,
},
function (accessToken, refreshToken, profile, done) {
User.findOne({
$or: [{ googleId: profile.id }, { googleId: null, email: profile.emails[0].value }],
}).then((user) => {
if (user === null) {
new User({
name: `${profile.name.givenName} ${profile.name.familyName}`,
email: profile.emails[0].value,
verified: true,
password: null,
picture: profile.photos[0].value,
googleId: profile.id,
})
.save()
.then((newUser) => {
userLimit()
console.log('newUser: ', newUser)
done(null, newUser)
})
.catch((err) => done(err, null))
} else if (user.googleId === profile.id) {
done(null, user)
} else if (user.googleId === null) {
done(null, false)
}
})
}
)
)
//=============================================================================
// OAuth2.0 Local Start
//=============================================================================
passport.use(
new LocalStrategy((username, password, done) => {
User.findOne({ email: username }, (err, user) => {
if (err) throw err
if (!user) return done(null, false)
if (user.googleId !== null) return done(null, false)
bcrypt.compare(password, user.password, (err, result) => {
if (err) throw err
if (result === true) {
return done(null, user)
} else {
return done(null, false)
}
})
})
})
)

Related

Error: Failed to serialize user into session in my Node.js Passport PSQL web app

This is my passport-config.js file. It should show the user can be serialised but for some reason it is not working.
const LocalStrategy = require('passport-local').Strategy
const { pool } = require("./db-config");
const bcrypt = require('bcrypt')
function initialize(passport, getUserById) {
const authenticateUser = async (email, password, done) => {
console.log(email, password);
pool.query(
`SELECT * FROM users WHERE email = $1;`,
[email],
(err, results) => {
if (err) {
throw err;
}
console.log(results.rows);
if (results.rows.length > 0) {
const user = results.rows[0];
bcrypt.compare(password, user.password, (err, isMatch) => {
if (err) {
console.log(err);
}
if (isMatch) {
return done(null, user);
} else {
//password is incorrect
return done(null, false, { message: "Password is incorrect" });
}
});
} else {
// No user
return done(null, false, {
message: "No user with that email address"
});
}
}
);
};
passport.use(new LocalStrategy({ usernameField: 'email' }, authenticateUser))
passport.serializeUser((user, done) => done(null, user.id))
passport.deserializeUser((id, done) => {
return done(null, getUserById(id))
})
}
module.exports = initialize
I think it's something to do with the PSQL query and it not recognising the user id. Please help :)

how to convert this Callback Authentication to Promise in nodejs mongoose

I am using Nodejs Mongoose here But when i Try to replace Callback to promise It Gives me an error
(Failed to serialize user into session)
Please Help Me........
var localStrategy = require('passport-local').Strategy;
const user = require('./mongoBase/userSc.js');
const bcrypt = require('bcryptjs');
module.exports = function(passport) {
passport.use(new localStrategy({ usernameField: 'email' }, (email, password, done) => {
email = email.toLowerCase();
user.findOne({ email: email }, (err, data) => {
if (err) throw err;
if (!data) {
return done(null, false, { message: "User Doesn't Exists.." });
}
bcrypt.compare(password, data.password, (err, match) => {
if (err) {
return done(null, false);
}
if (!match) {
return done(null, false, { message: "Password Doesn't Match" });
}
if (match) {
return done(null, data);
}
});
});
}));
passport.serializeUser(function(user, cb) {
cb(null, user.id);
});
passport.deserializeUser(function(id, cb) {
user.findById(id, function(err, user) {
cb(err, user);
});
});
}
// ---------------
// end of autentication statregy
Here is my code for passport with spotify, maybe it could help you some. If your question is answered by this answer, please click the checkbox beside the answer.
module.exports = function(passport) {
passport.use(
new SpotifyStrategy(
{
clientID: 'CLIENT ID',
clientSecret: 'CLIENT SECRET',
callbackURL: 'http://localhost:8888/auth/spotify/callback',
},
async (accessToken, refreshToken, expires_in, profile, done) => {
// Do async operations
async function checking() {
// Do async operations
}
await checking();
return done(null, profile);
}
)
);
// Serialize
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});

Cannot read property 'admin' of undefined

I have this problem in the time i am in admin routes and i try to add a new article or a new image in my database , the same things happen even when i want to update something ....
this is my codes ?
exports.isAdmin = (req, res, next) => {
if (req.isAuthenticated() && res.locals.user.admin == 1) {
next();
} else {
req.flash("danger", "please log in as admin");
res.redirect("/users/login");
}
}
var LocalStrategy = require("passport-local").Strategy;
var User = require("../models/user");
var bcrypt = require("bcryptjs");
module.exports = function (passport) {
passport.use(new LocalStrategy(function (username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err)
console.log(err);
if (!user) {
return done(null, false, { message: "No user found" });
}
bcrypt.compare(password, user.password, function (err, isMatch) {
if (err) console.log(err);
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: "Wrong password" });
}
})
});
}));
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
}
Anyone one can help the problem is i think in res.locals.user.admin but in other admin routes works ok but only when i want to add a new and edit a think happen this problem

TypeError: User.findById is not a function on deserializeUser

i was working with passport auth (local and google strategy) and now it tells me "User.findById is not a function" on the "deserializeUser" function.
passport.js
const passport = require('passport');
const request = require('request');
const LocalStrategy = require('passport-local').Strategy;
const GoogleStrategy = require('passport-google-oauth').
const OAuthStrategy = require('passport-oauth').OAuthStrategy;
const OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
const User = require('../routes/user');
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
/**
* Sign in using Email and Password.
*/
passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
User.findOne({ email: email.toLowerCase() }, (err, user) => {
if (err) { return done(err); }
if (!user) {
return done(null, false, { msg: `Email ${email} not found.` });
}
user.comparePassword(password, (err, isMatch) => {
if (err) { return done(err); }
if (isMatch) {
return done(null, user);
}
return done(null, false, { msg: 'Invalid email or password.' });
});
});
}));
/**
* OAuth Strategy Overview
*
* - User is already logged in.
* - Check if there is an existing account with a provider id.
* - If there is, return an error message. (Account merging not supported)
* - Else link new OAuth account with currently logged-in user.
* - User is not logged in.
* - Check if it's a returning user.
* - If returning user, sign in and we are done.
* - Else check if there is an existing account with user's email.
* - If there is, return an error message.
* - Else create a new account.
*/
/**
* Sign in with Google.
*/
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
callbackURL: '/auth/google/callback',
passReqToCallback: true
}, (req, accessToken, refreshToken, profile, done) => {
if (req.user) {
User.findOne({ google: profile.id }, (err, existingUser) => {
if (err) { return done(err); }
if (existingUser) {
req.flash('errors', { msg: 'There is already a Google account that belongs to you. Sign in with that account or delete it' });
done(err);
} else {
User.findById(req.user.id, (err, user) => {
if (err) { return done(err); }
user.google = profile.id;
user.tokens.push({ kind: 'google', accessToken });
user.profile.name = user.profile.name || profile.displayName;
user.profile.gender = user.profile.gender || profile._json.gender;
user.profile.picture = user.profile.picture || profile._json.image.url;
user.save((err) => {
req.flash('info', { msg: 'Google account has been linked.' });
done(err, user);
});
});
}
});
} else {
User.findOne({ google: profile.id }, (err, existingUser) => {
if (err) { return done(err); }
if (existingUser) {
return done(null, existingUser);
}
User.findOne({ email: profile.emails[0].value }, (err, existingEmailUser) => {
if (err) { return done(err); }
if (existingEmailUser) {
req.flash('errors', { msg: 'There is already an account using this email address. Sign in to that account and link it with Google manually from Account Settings.' });
done(err);
} else {
const user = new User();
user.email = profile.emails[0].value;
user.google = profile.id;
user.tokens.push({ kind: 'google', accessToken });
user.profile.name = profile.displayName;
user.profile.gender = profile._json.gender;
user.profile.picture = profile._json.image.url;
user.save((err) => {
done(err, user);
});
}
});
});
}
}));
exports.isAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/login');
};
/**
* Authorization Required middleware.
*/
exports.isAuthorized = (req, res, next) => {
const provider = req.path.split('/').slice(-1)[0];
const token = req.user.tokens.find(token => token.kind === provider);
if (token) {
next();
} else {
res.redirect(`/auth/${provider}`);
}
};
it was working before i copy paste to another directory and nothing.
SO, it was a structure problem, found and fixed.

Node.js Passport strategy login with either Email or Username

I am using Passport on my node.js app and I am currently using an Username to login.
On my user register page, I have allow the user to register their unique username and email.
I want a login page with "Sign in Using username/email:" ________
Where the script can detect if there is a "#" in the field and look up the email instead of username.
I have tried for a few hours with no avail.
here is my passport.js
var mongoose = require('mongoose')
var LocalStrategy = require('passport-local').Strategy
var User = mongoose.model('User');
module.exports = function(passport, config){
passport.serializeUser(function(user, done){
done(null, user.id);
})
passport.deserializeUser(function(id, done) {
User.findOne({ _id: id }, function (err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
}, function(username, password, done) {
User.isValidUserPassword(username, password, done);
}));
}
EDIT: below is the user.js as requested
var mongoose = require('mongoose');
var hash = require('../util/hash.js');
UserSchema = mongoose.Schema({
username: String,
email: String,
salt: String,
hash: String
})
UserSchema.statics.signup = function(username, email, password, done){
var User = this;
hash(password, function(err, salt, hash){
if(err) throw err;
// if (err) return done(err);
User.create({
username : username,
email: email,
salt : salt,
hash : hash
}, function(err, user){
if(err) throw err;
// if (err) return done(err);
done(null, user);
});
});
}
UserSchema.statics.isValidUserPassword = function(username, password, done) {
this.findOne({username : username}, function(err, user){
// if(err) throw err;
if(err) return done(err);
if(!user) return done(null, false, { message : 'Incorrect username.' });
hash(password, user.salt, function(err, hash){
if(err) return done(err);
if(hash == user.hash) return done(null, user);
done(null, false, {
message : 'Incorrect password'
});
});
});
};
var User = mongoose.model("User", UserSchema);
module.exports = User;
Ok, you should have something like this in your Mongoose model:
UserSchema.statics.isValidUserPassword = function(username, password, done) {
var criteria = (username.indexOf('#') === -1) ? {username: username} : {email: username};
this.findOne(criteria, function(err, user){
// All the same...
});
};
its a mongoose thing rather than a passport thing, and if you can try out this, using bredikhin's answer ^_^ :
var criteria = {$or: [{username: username}, {email: username}, {mobile: username}, {anything: username}]};
The key is to find a user through a query from mongodb!!!
In this way, you can have whatever query you want to find a user.
For sign ins with username OR email, you could also use passport-local-mongoose's findByUsername option modify the queryParameters
// add passport functions
// schema.plugin(passportLocalMongoose);
schema.plugin(passportLocalMongoose, {
// allow sign in with username OR email
findByUsername: function(model, queryParameters) {
// start
// // queryParameters => { '$or' : [ { 'username' : 'searchString' } ] }
// iterate through queryParameters
for( let param of queryParameters.$or ){
// if there is a username
if( typeof param == "object" && param.hasOwnProperty("username") ){
// add it as an email parameter
queryParameters.$or.push( { email : param.username } );
}
}
// expected outcome
// queryParameters => { '$or' : [ { 'username' : 'searchString' }, { 'email' : 'searchString' } ] }
return model.findOne(queryParameters);
}
});
its very simple you have to redefine the passport strategy your self, just like in the code below,
serialize with username
passport.serializeUser(function(user, done) {
done(null, user.username);});
deserialize with username
passport.deserializeUser(function(username, done) {
User.findOne({username:username},function(err, user){
done(err,user);
}); });
Passport Strategy
//passport strategy
passport.use(new LocalStrategy(function(username, password, done) {
console.log(username.includes("#"));
User.findOne((username.includes("#"))?{email:username}:{username:username}, function(err, user) {
if (err) {return done(err); }
if (!user) {console.log("i am ERROR"); return done(null, false, { message: 'Incorrect username.' });}
if (user.password===password) {return done(null, user); }
return done(null, false);
});
}
));
NOTE: Here user.password===password means that the password in database is stored as plaintext.. And you have to insert password manually to database such as password : req.body.password also you have to apply encryption and decryption user self before adding or in comparing.
Or you just make a middle-ware to handle the situation like so:
const User = require("../models/user");
var middlewareObj = {};
middlewareObj.checkUsername = function (req, res, next) {
if (req.body.username.indexOf('#') !== -1) {
User.findOne({ email: req.body.username }, (err, foundUser) => {
if (err || !foundUser) {
req.flash('error', 'Please check your username or password');
return res.redirect('/login');
} else {
req.body.username = foundUser.username;
next();
}
});
} else {
next();
}
}
module.exports = middlewareObj;
And simply add it to the login route:
app.post('/login', middleware.checkUsername, function (req, res, next) {
//Login logic goes here
}

Categories

Resources