Related
I am using passport and trying to do my code organisation like routes(just one line route), controller with one method to handle route, model to do some action which coming from controller method. Following code is working fine returning me token if mobile number and password is matched. But how can I reorgnize code so it break and become properly, I dont' want to put anything in routes.js file but just one single line, and nothing in controller but one method where I want to put all passport stuff in passport.js file either config/passport.js or root/passport.js
const express = require('express'),
cors = require('cors'),
compression = require('compression'),
morgan = require('morgan'),
passport = require('passport')
const app = express()
app.use(passport.initialize())
app.use(express.json())
app.use(express.urlencoded({extended: false}))
app.use('/', Router)
Now in my config/routes.js file
const passport = require('passport')
const userController = require('../app/controllers/users_controller')
const jwt = require('jsonwebtoken')
LocalStrategy = require('passport-local').Strategy
passport.use(
new LocalStrategy(function (username, password, done) {
User.findOne({mobile: username}, function (err, user) {
if (err) {
return done(err)
}
if (!user) {
return done(null, false, {message: 'Incorrect Username'})
}
console.log(` Password: ${password} `)
if (!user.comparePassword(password)) {
return done(null, false, {message: 'Incorrect password'})
}
return done(null, user)
})
})
)
passport.serializeUser(function (user, cb) {
cb(null, user.id)
})
passport.deserializeUser(function (id, cb) {
User.findById(id, function (err, user) {
if (err) {
return cb(err)
}
cb(null, user)
})
})
router.post('/api/v1/login', function (req, res, next) {
passport.authenticate('local', {session: false}, (err, user, info) => {
if (err || !user) {
return res.status(400).json({
message: 'Something is not right',
user: user,
})
}
req.login(user, {session: false}, (err) => {
if (err) {
res.send(` Error: ${err}`)
}
// generate a signed son web token wtih contents of user
const token = jwt.sign(user.id, 'your_jwt_secret')
return res.json({user, token})
})
})(req, res)
})
I want to break it, it should not be in routes, my other routes are like following
router.get('/logout', users_controller.update)
router.post('/forgotPassword', users_controller.update)
I want to that it should be like following route
router.post('/login', users_controller.login)
I tried many times but still can't work out, even used this code, but in my another website I used same method and it worked in Controller, so all passport related stuff I put in controller but that one is also not correct, it should be one line in route file and method in controller rest in separate passport.js files.
Kindly can you assist me how can I do it?
I'm trying to create an application that utilizes a registration and login functionality. I have completed the registration portion where all the information (Email and Password) is successfully passed and saved into a MySQL database.
Problem: My issue now is that when I put in any existing credential and email, the application will hang and refuse to redirect the user to a new page. On the bottom of my browser, it will say "Waiting for localhost...". If I leave the page up for too long, it'll eventually lead to an error page with the words "This page isn’t working. localhost didn’t send any data. ERR_EMPTY_RESPONSE".
I tried console logging for any errors but was unable to identify any causes/errors. I did ensure that the information I inputted is properly being compared to the values in the database table and that the redirection to the page is functioning. I also tried rewriting my code in multiple ways but ended up encountering the same issue.
Below is my passport.js file:
var LocalStrategy = require('passport-local').Strategy;
// Load User model
const User = require('../models/User');
// Reference: http://www.passportjs.org/docs/
module.exports = function (passport) {
passport.use(
new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
// Match user
User.findOne({ which: { email: email } })
.then(user => {
// Check if Email exists in database
if (!user) {
return done(null, false, {
message: "Email is not registered."
});
}
// Check if password matches the one found in the database (To Do: Encrypt this later!)
if (password != user.password) {
return done(null, false, { message: 'Password is incorrect.' });
} else {
return done(null, user);
}
})
.catch(err => console.log(err));
})
);
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
// Find by Primary Key
User.findByPk(id, function (err, user) {
console.log(user);
done(err, user);
});
});
}
Below is my app.js (server) file:
var express = require('express')
var expressLayouts = require('express-ejs-layouts');
var flash = require('connect-flash');
var session = require('express-session');
var passport = require('passport');
var app = express();
// Embedded JavaScript (EJS)
app.use(expressLayouts);
app.set('view engine', 'ejs');
// Express Session
app.use(session({
secret: 'secret',
resave: false,
saveUninitialized: false
}));
// Bodyparser
app.use(express.urlencoded({ extended: false }));
// Passport
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);
// Connect flash for notification messages
app.use(flash());
// Global Variables to define specific notification messages
app.use((req, res, next) => {
// Notification for Registration Page
res.locals.success_msg = req.flash('success_msg')
res.locals.error_msg = req.flash('error_msg');
// Notification for Passport Login Verification
res.locals.error = req.flash('error');
next();
});
// Routes
app.use('/', require('./routes/index'));
// Login/Register Endpoints routes (ex. /users/login)
app.use('/users', require('./routes/users'));
// Image
//app.use(express.static('./public'));
var port = process.env.PORT || 8026;
app.listen(port);
console.log('Server Running');
console.log("Port: " + port);
Below is my function to handle the login and redirection:
router.post('/login', (req, res, next) => {
console.log(req.body);
passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
});
Please let me know if you need any other information. Thank you!
I think this could be a problem. On passport.use , if an error occurred, you are not returning anything.
passport.use(
new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
// Match user
User.findOne({ which: { email: email } })
.then(user => {
// Check if Email exists in database
if (!user) {
return done(null, false, {
message: "Email is not registered."
});
}
// Check if password matches the one found in the database (To Do: Encrypt this later!)
if (password != user.password) {
return done(null, false, { message: 'Password is incorrect.' });
} else {
return done(null, user);
}
})
.catch(err =>{
console.log(err));
return done(null, false, { message: 'Internal Server error.' });
}
})
Fixed the hanging issue. It was indeed something wrong with the way I wrote passport.js as the code works more for MongoDB rather than MySQL.
Here is the new working passport.js:
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
connection.query("select * from users where id = "+id,function(err,rows){
done(err, rows[0]);
});
});
passport.use(new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows pass back of entire request to the callback
},
function(req, email, password, done) { // callback with email and password from form
// Match User
connection.query("SELECT * FROM `users` WHERE `email` = '" + email + "'",function(err,rows){
if (err)
return done(err);
// Check if Email exists in database
if (!rows.length) {
return done(null, false, { message: 'Email is not registered' });
}
// Check if password matches the one found in the database (To Do: Encrypt this later!)
if (!( rows[0].password == password))
return done(null, false, { message: 'Password is incorrect.' });
// All is well, return successful user
return done(null, rows[0]);
});
}));
};
Background
I recognize that this question has been asked a million times, but none of said questions ever fixed my problem. In my apps routes, calling req.user only ever returns undefined, regardless of which route I'm accessing.
My login feature works fine as well, if this helps. I have specific elements of my client change when logged in/not, but req.user returns undefined regardless.
As many have pointed out for similar questions, it's probably a slip-up in the ordering of my middleware, but I can't for the life of me find it as my ordering is practically copy/pasted from around ~3 different places.
The general layout of my app is one main file, app.js, that sets up my express app and contains all of my routes. All of my routes are places below my middleware setup.
Relevant app.js Code
// Middleware
// Setup DB Pool and app
var pool = mysql.createPool(db.pool);
var app = express();
// Setup Handlebars
app.engine('handlebars', exprhbr({defaultLayout: 'index'}));
app.set('view engine', 'handlebars');
app.use(express.static('public'));
// Setup body parser
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Setup session
app.use(session({
cookie: { maxAge: 60000 },
secret: 'spooky',
resave: true,
saveUninitialized: true
}));
// Setup passport
app.use(passport.initialize());
app.use(passport.session());
...
// An example route
app.get('/', (req, res) => {
let loggedIn = req.isAuthenticated(); // works perfectly
console.log('user: ', req.user); // always prints "user: undefined"
res.status(200).render('home', {
page: 'Home',
noSearch: true,
loggedIn: loggedIn,
user: req.body.username
});
});
// My login route
app.post('/login', (req, res, next) => {
if (verify.login(req.body)) {
passport.authenticate('local', {
session: true,
successRedirect: '/user/' + req.body.username,
failureRedirect: '/login'
})(req, res, next);
}
});
Passport
I initialize passport using:
require('./src/passport')(passport);
at the top of my file, and said passport file looks like this:
Relevant passport.js Code
var strategy = require('passport-local').Strategy;
var bcrypt = require('bcrypt');
var mysql = require('mysql');
var db = require('./database');
var pool = mysql.createPool(db.pool);
module.exports = (passport) => {
passport.serializeUser((user, done) => {
done(null, user.uid);
});
passport.deserializeUser((uid, done) => {
pool.query('SELECT * FROM User WHERE (user_id = ?)', [uid], (err, result) => {
done(err, {uid: result[0].user_id, username: result[0].username, pass: result[0].password});
});
});
// Setup Passport
passport.use(new strategy({ usernameField: 'username' }, (username, pass, done) => {
// Match a user
pool.query('SELECT * FROM User Where (username = ?)', [username], (err, result) => {
if (!result.length) return done(null, false, {message: 'Username isn\'t registered'});
let user = result[0];
// User was found so decrpt pass
bcrypt.compare(pass, user.password, (err, isMatch) => {
if (err) throw err;
// User matches
if (isMatch)
return done(null, {uid: user.user_id, username: username, pass: user.password});
else
done(null, false, {message: 'Password doesn\'t match'})
});
});
}));
}
Swapping around the ordering of my function declarations does nothing if that helps at all.
Thanks for taking the time to read this long post, and for possibly helping me out!
As it stands right now, my site logs you out after a few page refreshes, and most of the time, I don't notice this happening.
My problem arose because I was checking req.user for a user that wasn't logged in, thus the only logical thing for it to return was undefined. Because I didn't notice I was logged out, I assumed it printed undefined regardless of a user being logged in.
I fixed this issue by first confirming the existence of a logged in user by checking if req.user exists, and then setting variables accordingly.
I am using express and passport to build a rest api backend and it seems that my localStrategy is not getting called on request.
The entry point of my application looks like the following:
app.js
var fs = require('fs');
var express = require('express');
var mongoose = require('mongoose');
var passport = require('passport');
var config = require('./config/config');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var app = express();
app.use(morgan('dev')); // log every request to the console
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser.urlencoded({extended:true}));
app.use(passport.initialize());
//connect to mongodb
mongoose.connect(config.db, options);
//load models (shorten forEach)
...
require(__dirname + '/models/' + file)(mongoose);
//load passport config
require('./config/passport')(mongoose, passport);
//load routes
require('./config/routes')(app, passport);
//start server
var server = app.listen(3000, ....
routes.js
...
app.post('/auth', function(req, res){
console.log("reached auth endpoint");
console.log(req.body);
passport.authenticate('local', { session: false}, function(err, user, info){
console.log("Test:"+user);
if(err) {
console.log("Error1");
return next(err)}
if(!user){
console.log("Error2");
return res.json(401, {error: 'Auth Error!'});
}
console.log("Error3");
var token = jwt.encode({ username: user.email }, "hanswurst");
res.json({token: token});
}),
function(req, res){
console.log("passport user", req.user);
};
});
passport.js
...
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function(email, password, done){
console.log("TEST");
User.findOne({'email': email}, function(err, user){
if(err){
console.log("Unknown error");
return done(err);
}
if(!user){
console.log("No User found");
return done(null, false);
}
if(!user.validPassword(password)){
console.log("Password was incorrect");
return done(null, false);
}
console.log("User was found");
return done(null, user);
});
}
));
The only result i get on form request is
reached auth endpoint
{ email: 'test#mail.com', password: 'secret' }
POST /auth - - ms - -
For me the request body looks fine and it should enter my LocalStrategy. I am bit helpless as i am not getting any other console output from this point.
First off, you have some basic javascript syntax errors in routes.js. This part right here (lots of code removed for clarity) is broken:
passport.authenticate(/*...*/), function(req, res) {/*..*/};
It might have been that you just added some console.log calls in the wrong place. To clear up the confusion, passport.authenticate() does not perform the authentication right away, what it does is return a middleware for you. You would use it like this for example :
var middleware = passport.authenticate(...);
app.post('/auth', middleware);
So to fix your problem, try invoking the middleware returned by authenticate right away, like this:
app.post('/auth', function(req, res, next) {
console.log("reached auth endpoint");
console.log(req.body);
passport.authenticate('local', {
session: false
}, function(err, user, info) {
console.log("Test:" + user);
if (err) {
console.log("Error1");
return next(err);
}
if (!user) {
console.log("Error2");
return res.json(401, {
error: 'Auth Error!'
});
}
console.log("Error3");
var token = jwt.encode({
username: user.email
}, "hanswurst");
res.json({
token: token
});
})(req, res, next);
});
Also, I have to tell you that require caches modules. To make config/passport.js aware of mongoose and passport, you should not feed them as parameters like this:
require('./config/passport')(mongoose, passport);
Simply require them again inside config/passport.js like so:
// (in config/passport.js)
// Both of these vars point to the same thing you require'd in app.js
var mongoose = require('mongoose');
var passport = require('passport');
[Edit] I Found the problem. Because Express is no longer supporting subpackages like body-parser etc, you need to set those separately. All would be well had I done that in the first place, but I only activated:
app.use(bodyParser.urlencoded({extended:true}));
You also need to set
app.use(bodyParser.json());
To get it to work properly. Stupid oversight but still, got me stumped for 3 days.
I Have the same problem, but nothing seems to work for me though.
I'll drop the code from the top down in execution order
jade template
.navbar-right(ng-controller="mvNavBarLoginCtrl")
form.navbar-form
.form-group
input.form-control(placeholder='Email', ng-model='username')
.form-group
input.form-control(type='password', placeholder='password', ng-model='password')
button.btn.btn-primary(ng-click="signIn(username,password)") Sign In
Next step Login controller
angular.module('app').controller('mvNavBarLoginCtrl',function($scope, $http){
$scope.signIn = function (username, password){
console.log('un = ' + username); // Prints fine in the console
console.log('pw = ' + password); // Prints fine in the console
$http.post('/login', {username: username, password: password}).then(function(response){
if(response.data.success){
console.log('Logged in!!');
}
else{
console.log('Failed to log in!!');
}
});
}
});
Next step Route handler
app.post('/login', function(req, res, next){
console.log(req.username); // Already empty
console.log(req.password); // Already empty
console.log(req.body); // Already empty
// Because of the use of AngularJS we can not call passport directly,
// missing req and res will break the code
var auth = passport.authenticate('local', function(err, user){
console.log(user); // prints undefined
if(err){return next(err);}
if(!user){res.send({success:false});}
req.logIn(user, function(err){
if(err){return next(err);}
res.send({success: true, user: user});
});
});
// call the auth function to start authenticate
auth(req, res, next);
});
Next step passport authentication handler
var User = mongoose.model('User');
passport.use(new LocalStrategy({
username: 'username',
password: 'password'
},
function(username, password, done){
console.log("called"); // never printed
// find user based in mongoose schema see 'var User'
User.findOne({userName:username}).exec(function (err,user){
console.log(user) // never printed
if(err){return done(err);}
if(user){
return done(null, user);
}
else{
return done(null, false);
}
});
}
));
passport.serializeUser(function(user, done){
if(user) {
done(null, user._id);
}
});
passport.deserializeUser(function(id, done){
user.findOne({_id:id}).exec(function(err, user){
if(user) {
done(null, user);
}
else{
done(null, false);
}
});
});
There are no errors not in the console and not as node output. I am stumped and read about 5 or so other thread with similar issues, nothing worked.
If somebody could give me the golden tip, I would be eternally gratefull.
Hi guys I need some help understanding node.js syntax. The application has put parameters on a require function that requires a path to another file ( not a module). let me give you an example of the syntax that I am talking about which is located on the main javascript file called server.js.
require('./config/passport')(passport);
and
require('./app/routes.js')(app, passport);
I need to know why these "app" and "passport" parameters are passed to my require function. app is express and passport is the passport module.
the full relevant files are below. Cheers
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
require('./app/models/user');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var configDB = require('./config/database.js');
mongoose.connect(configDB.url);
require('./config/passport')(passport);
app.use(morgan('dev')); //http request logger
app.use(cookieParser()); //reads cookies (needed for authentication)
app.use(bodyParser()); //gets information from html forms
app.set('view engine', 'ejs');
//required for passport
app.use(session({secret: 'jonathanisawesome'}));
app.use(passport.initialize());
app.use(passport.session()); //persistent login sessions
app.use(flash()); //connect-flash for flash messages stored in sessions
//routes
require('./app/routes.js')(app, passport); //loads our routes and passes in our app and fully configured passport
app.listen(port);
console.log('the magix happens on port ' + port);
app.get('/logout', function(req,res){
req.logout();
res.redirect('/');
});
//processing of the form
app.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login',
failureFlash : true
}));
app.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash : true
}));
// route for facebook authentication and login
app.get('/auth/facebook', passport.authenticate('facebook', { scope : 'email' }));
// handle the callback after facebook has authenticated the user
app.get('/auth/facebook/callback',
passport.authenticate('facebook', {
successRedirect : '/profile',
failureRedirect : '/'
}));
app.get('/auth/google', passport.authenticate('google', { scope : ['profile', 'email'] }));
// the callback after google has authenticated the user
app.get('/auth/google/callback',
passport.authenticate('google', {
successRedirect : '/profile',
failureRedirect : '/'
}));
};
//route middleware to make sure a user is logged in
function isLoggedIn(req,res,next){
//if user is authenticated in the session, carry on
if(req.isAuthenticated())
return next();
//if they are not, redirect them to the homepage
res.redirect('/');
};
var LocalStrategy = require('passport-local').Strategy;
var FacebookStrategy = require('passport-facebook').Strategy;
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
var User = require('mongoose').model('User');
var configAuth = require('./auth');
var crypto = require('crypto');
module.exports = function(passport){
//passport session setup
//persistent login sessions
//passport needs ability to serialize and unserialize users out of sessions
//use to serialize the user for the session
passport.serializeUser(function(user,done){
done(null, user.id);
});
//deserialize user
passport.deserializeUser(function(id,done){
User.findById(id, function(err, user){
done(err, user);
});
});
//local signup
//using named strategies one for login and one for signup
//by default if there was no name it would be called 'local'
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// create the user
var newUser = new User();
// set the user's local credentials
newUser.email = email;
newUser.password = password; //password is hashed on the model layer
// save the user
newUser.save(function(err,user) {
if(err || !user){
//error handling
if(err.code===11000){ //email taken
return done(null, false, req.flash('signupMessage', 'Sorry, the email '+newUser.email+' has been taken'));
}else{ //its a hacker
return done(null, false, req.flash('signupMessage', JSON.stringify(err)));
}
}else{
return done(null, newUser);
}
});
});
}));
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'email' : email }, function(err, user) {
// if there are any errors, return the error before anything else
if (err)
return done(err);
// if no user is found, return the message
if (!user)
return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash
// if the user is found but the password is wrong
if (!user.authenticate(password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
// all is well, return successful user
return done(null, user);
});
}));
//facebook
passport.use(new FacebookStrategy({
clientID: configAuth.facebookAuth.clientID,
clientSecret: configAuth.facebookAuth.clientSecret,
callbackURL: configAuth.facebookAuth.callbackURL
},
function(accessToken, refreshToken, profile, done) {
process.nextTick(function(){
User.findOne({'facebook.id': profile.id}, function(err, user){
if(err)
return done(err);
if(user)
return done(null, user);
else {
var newUser = new User();
newUser.email = profile.emails[0].value;
newUser.password = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
newUser.socialLogin.facebook.id = profile.id;
newUser.socialLogin.facebook.token = accessToken;
newUser.socialLogin.facebook.name = profile.name.givenName + ' ' + profile.name.familyName;
newUser.socialLogin.facebook.email = profile.emails[0].value;
newUser.save(function(err){
if(err) console.log(err)
return done(null, newUser);
})
console.log(profile);
}
});
});
}
));
passport.use(new GoogleStrategy({
clientID : configAuth.googleAuth.clientID,
clientSecret : configAuth.googleAuth.clientSecret,
callbackURL : configAuth.googleAuth.callbackURL,
},
function(token, refreshToken, profile, done) {
// make the code asynchronous
// User.findOne won't fire until we have all our data back from Google
process.nextTick(function() {
// try to find the user based on their google id
User.findOne({ 'google.id' : profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
// if a user is found, log them in
return done(null, user);
} else {
// if the user isnt in our database, create a new user
var newUser = new User();
newUser.email = profile.emails[0].value;
newUser.password = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
newUser.socialLogin.google.id = profile.id;
newUser.socialLogin.google.token = token;
newUser.socialLogin.google.name = profile.displayName;
newUser.socialLogin.google.email = profile.emails[0].value; // pull the first email
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
};
This:
require('./config/passport')(passport);
is roughly equivalent to this:
var pp = require('./config/passport');
pp(passport);
To explain, require('./config/passport') returns a function that expects one argument. You can call that function directly in the first form above or you can assign it to a variable and then call it.
Take this example:
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
app.use(session({
secret: 'foo',
store: new MongoStore(options)
}));
As you can see MongoStore is meant to be used alongside session, so it depends on that module.
require('./config/passport') returns a function which expects passport as its parameter.
I faced the problem using require('./config/passport')(passport) so I got solution as:
const passConfig = () => {
return require('./config/passport')
}
passConfig(passport)