passport-local with ajax does not use session - javascript

When doing an async login to passport-local my session never stores a user and the serialization is never called.
Since I'm not redirecting when I'm done logging in (I just notify the user about it through the response to their ajax call) I guess I'll have to trigger the serialization manually when I've logged in? I'm not sure how the session will have the user associated when they refresh though. This is my main concern since my users never leave the main page in my use case, I do however want them to stay logged in for some period of time after they refresh (unless they explicitly log out).
Any ideas how I can cause passport to save the session when I'm logging in with ajax?
Configuration
app.use(require('express-session')({secret:'secret'}));
app.use(passport.initialize());
app.use(passport.session());
app.get('/', function(req, res) {
res.render('index', {
user: req.user // undefined here, although req.session does exist. req.session.passport does not exist.
});
});
app.post('/login', function(req, res, next) {
passport.authenticate('local-login', {}, function(error, user, info) {
if (error) {
return res.status(500).json(error);
}
if (!user) {
return res.status(401).json(info);
}
res.json({user: user});
})(req, res, next);
});
Login call, client side
$.ajax({
url: "/login",
type: "POST",
contentType: "application/json",
data: '{"email":"a#b.c", "password":"abc"}',
cache: false,
timeout: 5000,
success: function(data) {
data.user; // valid, this comes back.
}
});
Serialization (never called)
passport.serializeUser(function(user, done) {
console.log('serialize user:', user); // never called
done(null, user);
});
passport.deserializeUser(function(id, done) {
console.log('deserializeUser user:', user); // never called
User.findById(id, function(err, user) {
console.log('deserializeUser user (done):', user);
done(err, user);
});
});
Strategy
var onLocalLoginStrategy = function(req, email, password, done) {
User.findOne({
'local.email': email.toUpperCase()
}, function(err, user) {
if (err)
return done(err);
if (!user)
return done(null, false, { message:'No user found.'} );
if (!user.validPassword(password))
return done(null, false, { message: 'Incorrect password.' });
return done(null, user);
});
};

Related

req.user not defined when calling from android application

I am making an android app in partnership with a colleague, he is an Android developer and I know very little about android dev. I do the backend stuff, I made the login and auth using node.js, express, and passport.js.
I hosted the server locally and used postman to check the auth and registration processes, all were working fine. I am getting the status codes my friend wanted for his Front-end. In the authentication part using passport.js when success I am passing req.user which should return the user body, so that my friend on the Front-end can use the field user.firstName from user object to display a welcome message.
Through Postman, the user body is getting defined and I am getting a user object with all fields in the Postman window, but through the app it is giving an error.
firstName is undefined property.
Passport.js logic:
const LocalStrategy = require('passport-local').Strategy;
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
//load user model
const User = require('../models/UserSchema');
module.exports = function(passport){
passport.use(
new LocalStrategy({usernameField: 'roll'}, (roll, password, done) => {
//find user
User.findOne({roll: roll})
.then(user =>{
if(!user){
return done(null, false, {message: 'Roll number not registered'});
}
//match password
bcrypt.compare(password, user.password, (err, isMatch) =>{
if(err) throw err;
if(isMatch){
return done(null, user);
}else{
return done(null, false, {message: 'Password incorrect'});
}
})
})
.catch(err => console.log(err));
})
);
/*passport.serializeUser( function(id, done) {
done(null, User.roll);
});
passport.deserializeUser(function(id, done){
User.findById(roll, function(err, user){
done(err, user);
});
});*/
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser((_id, done) => {
User.findById( _id, (err, user) => {
if(err){
done(null, false, {error:err});
} else {
done(null, user);
}
});
});
}
Login Route:
//Login Handle
router.post('/login', (req, res, next) =>{
console.log('/user/login')
passport.authenticate('local', {
successRedirect: '/success',
failureRedirect: '/failure',
session: true,
failureFlash: false
})(req, res, next);
//res.json(pass.user.name);
});
/success route:
router.get('/success', (req, res) => {
console.log(req);
let message = 'Login Succesful';
//let user = req.user.firstName
res.status(200).json({'message':message, 'user': req.user.firstName});
})
I guess you are also using body-parser or express.json() to parse the incoming body request to JSON. If this is the case you should send the response back like this:
req.body.user.firstName
For POST requests: req.body
For GET parameters: req.params
For GET query strings: req.query

PassportJS Authentication Failing every time (LocalStrategy)

I'm new to SO & Node / Passport so apologies in advance. I've been trying to work through the login portion of my site using Passport (already have registration working) for several days now with no success. I've tried several tutorials and read through the documentation, but at this point am more confused than when I started.
Problem: passport.authenticate function returns "user" as false despite the information being correct according to my database (MongoDB). I'm not getting any error messages, in /dologin route, the user value is false and info value is "Missing Credentials". Let me know if there is any other information I can provide - I appreciate the help!
Attempts: I've moved my code around to different functions, files etc. Tried different solutions found online, tried the documentation examples, wrote my own methods in my models. etc.
App.js file
app.use(session({
secret: 'secrettexthere',
saveUninitialized: true,
resave: true,
// using store session on MongoDB using express-session + connect
store: new MongoStore({
mongooseConnection: mongoose.connection
})
}));
// Init passport authentication
app.use(passport.initialize());
// persistent login sessions
app.use(passport.session());
passport.use(new LocalStrategy(
function(username, user_password, done) {
User.getUserByUsername(username, function(err,user){
console.log('in getUserByUsername');
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown user.'});
};
User.comparePassword(password, user.password, function(err,isMatch) {
if (err) throw err;
console.log('in comparepassword');
if(isMatch) {
console.log('isMatch');
return done(null, user);
} else { console.log('not match');
done(null, false, {message:'Invalid username or password.'})};
})
});
} ));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.getUserById(id, function(err, user) {
done(err, user);
});
});
Routing File (ideally will eventually move this to my controller but just want to get it working to some extent to start)
router.post('/dologin', function(req, res, next) {
console.log(req);
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { console.log('nomatch');
console.log(info);
console.log('');
console.log(user);
return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
console.log('match match match');
return res.redirect('/register');
});
})(req, res, next);
});
Model
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
};
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err,isMatch){
if (err) throw err;
callback(null, isMatch);
});
};
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
};

Authentication times out on login (passportJS) and I'm desperate

I'm very new to Passport & Node, I've been trying to solve an issue for several days without being able to find a solution that already exists on SO or the internet. I'm getting no errors or anything on login attempt, nothing in chrome dev, nothing in gitbash. Only problem is page never redirects, never seems to get through the passport.authenticate function inside my auth controller (/dologin). When I attempt a login, the browser never stops loading (ex. the circle keeps spinning for chrome), I have no problems with internet or anything of that nature, I only have this problem when implementing the login feature. One thing that I suspect might be an issue is that I do not have my localstrategy/serialization/deserialization in the right spot but I have tried it in app.js as well so at this point I'm really just too confused.
app.js - I tried including the initialize > session > localstrategy > serialize > deserialize in here, but it also didn't work so I just left initialize and session
// // Init passport authentication
app.use(passport.initialize());
// persistent login sessions
app.use(passport.session());
index.js
// route for login action
router.post('/dologin', auth.doLogin);
authController.js
passport.use(new LocalStrategy(
function (username, password, done) {
User.getUserByUsername(username, function (err, user) {
if (err) throw err;
if (!user) {
return done(null, false, { message: 'Unknown User' });
}
User.comparePassword(password, user.password, function (err, isMatch) {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Invalid password' });
}
});
});
}));
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.getUserById(id, function (err, user) {
done(err, user);
});
});
userController.doLogin = function(req, res) {
passport.authenticate('local', { successRedirect: '/', failureRedirect: '/doLogin', failureFlash: true }),
function (req, res) {
res.redirect('/');
}
};
users.js (model) - includes getUserByUsername, comparePassword, getUserbyId
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch){
if (err) throw err;
callback(null, isMatch);
});
}
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}

Passport callback isn't called

I build an application using Passport lib using this tutorial (part of it).
Note, I don't need a registration, only login form.
One of the issues is that my LocalStrategy callback is never called. For storing I use mongo:
mongoose.connect(dbConfig.url, {
useMongoClient: true
});
//dbConfig
module.exports = {
'url' : 'mongodb://localhost/passport'
}
Login route looks like this:
module.exports = function(app, passport) {
app.get('/login', function(req, res) {
res.render('login', {
message: req.flash('loginMessage')
});
});
app.post('/login', passport.authenticate('login', {
successRedirect: '/', // redirect to the secure profile section
failureRedirect: '/login', // redirect back to the signup page if there is an error
failureFlash: true // allow flash messages
}));
}
Passport logic is:
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use('login', new LocalStrategy({
passReqToCallback: true
}, function(req, username, password, done) {
console.log('start'); // never called
User.findOne({
'local.email': email
}, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, req.flash('loginMessage', 'No user found.'));
}
if (!user.validPassword(password)) {
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
}
return done(null, user);
});
}));
};
console.log('start'); is never called, although passport.authenticate('login' ...) is called.
What can be an issue?
I finally fixed it and everything works. In case anyone face the same issues I'm posting here several problems and solutions.
The req.body was empty in my app.post, because I didn't add body parser. Fixed it with:
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
Username field was empty all the time because I named it as email and passport expected username. Fixed with:
new LocalStrategy({
usernameField: 'email', // this parameter
passReqToCallback: true
}

How to add user in DB when using Passport.js? How to modify existing routes to require authentication?

Couple of questions. I set up authentication in my app using the following code:
passport.use(new LocalStrategy(function(username, password, done){
Users.findOne({ username : username},function(err,user){
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' });
});
});
}));
app.get('/admin', function (req, res){
res.render('login.jade');
});
app.post('/admin', function (req, res){
passport.authenticate('local', { successRedirect: '/main',
failureRedirect: '/login',
failureFlash: true });
});
Users is a DB schema that includes username, password, and hash.
The first and most obvious question is, how do I add a new user to the database? I specifically don't want a sign-up page but want to manually add every new user. Is there a way to do this manually?
Next, how do I modify my existing routes to only work if the user is authenticated? For example, I have:
app.get('/comment/:commentID', admin.renderComment);
The above renderCommit is a large handler function but accessing this page should only work if the user is authenticated. How do I check that?
Creating a new user should be relatively straightforward, from a standalone script for instance:
// Load your models, set up database connection, etc.
...
// Create a new user:
Users.create({
username : USERNAME,
password : HASHED_PASSWORD,
salt : GENERATED_SALT,
}, function(err, user) {
if (err) {
console.error('Error creating user:', err.message);
} else {
console.log('User created successfully');
}
});
As for making sure that a user is logged in when certain routes are requested, you can use a simple middleware for that:
app.get('/comment/:commentID', ensureAuthenticated, admin.renderComment);

Categories