I have a login created in Express with the use of Passport.js. Now I have everything setup and when username and password are correct it will redirect to the user page. But now I want to show a message when the credentials are incorrect. Right now it leads to a blank page with an auto message of 'unauthorized'
This is my passport.js setup:
App.js:
var mongoose = require('mongoose');
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost:27017/homeapp');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
app.use(require('express-session')({
secret: 'testtest',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
var User = require('./models/User');
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
Index.js
var express = require('express');
var router = express.Router();
var auth = require('../controller/AuthController.js');
router.get('/', auth.home);
router.get('/login', auth.login);
router.post('/login', auth.doLogin);
router.get('/logout', auth.logout);
module.exports = router;
Users.js:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
var UserSchema = new Schema({
username: String,
password: String
}, {collection: 'userdata'});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model('User', UserSchema);
AuthController.js:
var mongoose = require("mongoose");
var passport = require("passport");
var User = require("../models/User");
var userController = {};
userController.home = function(req, res) {
res.render('index', { user : req.user });
};
userController.login = function(req, res) {
res.render('login');
};
userController.doLogin = function(req, res){
passport.authenticate('local')(req, res, function(){
res.redirect('/');
});
};
userController.logout = function(req, res) {
req.logout();
res.redirect('/');
};
module.exports = userController;
You can do modification in your code like this :
userController.doLogin = function(req, res){
passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login',
failureFlash: true })
passport.authenticate('local', { failureFlash: 'Invalid username or
password.' });
};
Setting the failureFlash option to true instructs Passport to flash an error message using the message given by the strategy's verify callback, if any. This is often the best approach, because the verify callback can make the most accurate determination of why authentication failed.
As ,i have seen you are using passport custom callback method for this you can do like this:
userController.doLogin = function(req, res){
passport.authenticate('local', function(err, user) {
if (err) { return next(err); }
if (!user) { return res.json('invalid credentials'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/');
});
})(req, res);
};
Related
I am currently creating a small user authentication app using Node + Express + Passport. When the user logs in, they are rerouted automatically to the index page "/" and a session should be established with passports authentication. For some reason when trying to console.log(req.user), it is returning "undefined".
The authentication with passport seems to be working properly with the post route
app.post("/login", passport.authenticate("local", {
successRedirect: "/home",
failureRedirect: "/login"
}), (req, res) => {
})
But the session is not being established with the user model. I'd like to eventually store the userId in the session. Here is a look at my current set up with user model and passport implementation on the server file.
const mongoose = require("mongoose");
const passportLocalMongoose = require('passport-local-mongoose');
const userSchema = mongoose.Schema({
username: String,
email: String,
password: String
});
userSchema.plugin(passportLocalMongoose);
const user = mongoose.model("User", userSchema);
module.exports = user;
-----------------------------------------------------------------------------------------
const express = require("express"),
mongoose = require("mongoose"),
bodyParser = require("body-parser"),
session = require("express-session"),
User = require("./models/user"),
passport = require('passport'),
LocalStragety = require('passport-local'),
app = express();
mongoose.connect("mongodb://localhost/shopping_cart_app", { useNewUrlParser: true })
.then(console.log("MongoDB Connected"))
.catch(err => console.log(err));
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname + '/views'));
app.use(session({
secret: "secret",
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStragety(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.post("/login", passport.authenticate("local", {
successRedirect: "/home",
failureRedirect: "/login"
}), (req, res) => {
})
I've tried looking into Passports config a bit more but on the documentation provided, it states that once passport.authenticate runs, a session with the user is established. Any tips would be greatly appreciate.
Thanks
I know this may seem simple, but have you tried req.body.user?
The req.body contains the data submitted by the user. The documentation suggest that you use a body parser to populate the information because it's undefined by default. However, instead of using the app object I use express router without parsing.
const express = require("express");
const router = express.Router();
router.post("/login", passport.authenticate("local", {
successRedirect: "/home",
failureRedirect: "/login"
}), (req, res) => {
console.log(req.body.user);
})
for more information: req.body
Try this one, In my project, it is working.
LocalStrategy
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var admins = mongoose.model('admins');
var bCrypt = require('bcrypt-nodejs');
var flash = require('connect-flash');
var moment = require('moment');
// User
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(obj, done) {
console.log("deserializing " + obj);
done(null, obj);
});
passport.use('adminlogin',new LocalStrategy(
function(username, password, done) {
admins.findOne({ 'email' : username },
function(err, user) {
//console.log(username);
if (err)
return done(err);
if (!user){
//console.log('Username '+username+' does not Exist. Pleasr try again.');
return done(null, false, { message: 'Incorrect Username/Password. Please try again.' });
}
if (!isValidPasswordAdmin(user, password)){
//console.log('Invalid Password');
return done(null, false, { message: 'Incorrect Password. Please try again.' });
}
return done(null, user);
}
);
})
);
var isValidPassword = function(user, app_pin){
return bCrypt.compareSync(app_pin, user.app_pin);
}
var isValidPasswordAdmin = function(user, password){
return bCrypt.compareSync(password, user.password);
}
module.exports = passport;
Login Route
router.post('/login', function (req, res, next) {
admins.find({}, function (err, user) {
if (err) {
console.log('internal database error');
req.flash('error', 'Database Error');
res.redirect('/admins');
} else {
passport.authenticate('adminlogin', function (err, user, info) {
if (err) {
console.log(err);
req.flash('error', 'Database Error');
res.redirect('/admins');
} else if (!user) {
req.flash('error', info.message);
res.redirect('/admins');
} else {
req.logIn(user, function (err) {
if (err) {
req.flash('error', 'Database Error');
res.redirect('/admins');
} else {
res.redirect('/admins/home');
}
});
}
})(req, res, next);
}
});
});
my app.js is
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var flash = require('connect-flash');
var session = require('express-session');
var passport = require('passport');
app.set('views', __dirname+'/views');
app.set('view engine', 'ejs');
app.use(bodyParser());
app.use(cookieParser());
app.use(session({secret : 'somthing'}));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
app.use(function(req, res, next){
res.locals.message = req.flash();
console.log(res.locals);
next();
});
app.use(require('./controller/router'));
// Default Controller Come Here
app.listen(3000, function(){
console.log('Running');
})
router.js is
var express = require('express');
var router = express.Router();
router.use('/', require('./home'));
router.use('/login', require('./login'));
router.use('/user', require('./user'));
module.exports=router;
passport.js (inside of config folder)
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var User = require('../model/users');
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
done(err, id);
});
passport.use(new LocalStrategy(function(username, password, done){
if(username == "test#test.com")
/* hardcore check username and password */
{
if(password=="123")
{
var result = { id : 1, fullname : "james", username : "jamesjoel"};
console.log("Success");
return done(result, true);
}
return done(null, false, { message : "Incorrect Passwordtttt"});
}
return done(null, false, { message : "Incorrect Username and password"});
}
));
module.exports=passport;
and finaly my login.js controller is
var passport = require('../config/passport');
var express = require('express');
var router = express.Router();
router.post('/', passport.authenticate('local', {
successRedirect: '/user',
failureRedirect: '/login',
failureFlash: true
})
);
router.get('/', function(req, res){
console.log(req.flash());
res.render('login', { msg : req.flash()});
});
module.exports=router;
but when i send correct username and password it show in console "success" and show [Object Object] and successRedirect not working infact i wrote somthing on .serializeUser() and .deserializeUser() its also not showing on console....
so please help me for this .....
done is a callback and it takes first argument as an error. But in your case after success still you are passing value as error try to make it null like this return done(null,result, true)
if(password=="123"){
var result = { id : 1, fullname : "james", username : "jamesjoel"};
console.log("Success");
return done(null,result, true);
}
I create express session in login.js route but i am unable to access in student.js route.It shows undefined.
Here is my login.js file
const express = require('express');
const router = express.Router();
const User = require('../models/users');
router.get('/', function(req, res, next){
res.render('login');
});
router.post('/login', function(req, res){
let email = req.body.email;
let password = req.body.password;
//console.log(email +" and "+password);
User.findOne({"email" : email, "password" : password}, function(err, user){
if(err){
console.log(err);
return res.status(500).send();
}
if (!user) {
return res.status(404).send();
}
//console.log(user.email);
console.log("Login success");
req.session.sess = user;
//console.log(req.session.sess.email);
res.send({login:true});
})
});
router.get('/usersdata',function(req, res){
User.find(function(err, data){
res.send(data);
})
})
module.exports = router;
this is my student.js file
const express = require('express');
const router = express.Router();
router.get('/', function(req, res, next) {
console.log(req.session.sess);
if (req.session.sess) {
res.render('student/studentHome');
} else {
res.render('./login');
}
});
module.exports = router;
express session declaration
app.use(session({
secret: '<secret key>',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
how to access session in another route .
I saw a couple of post with similar to mine but I still getting the same error
here is my user schema
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var userSchema = mongoose.Schema({
local: {
email: String,
password: String,
},
});
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
module.exports = mongoose.model('User', userSchema);
my routes
var express = require('express');
var passport = require('passport');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.get('/login', function(req, res, next) {
res.render('login.ejs', { message: req.flash('loginMessage') });
});
router.get('/signup', function(req, res) {
res.render('signup.ejs', { message: req.flash('loginMessage') });
});
router.get('/profile', isLoggedIn, function(req, res) {
res.render('profile.ejs', { user: req.user });
});
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash: true,
}));
router.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login',
failureFlash: true,
}));
module.exports = router;
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
my app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var flash = require('connect-flash');
var session = require('express-session');
var routes = require('./routes/index');
var users = require('./routes/users');
var configDB = require('./config/database.js');
mongoose.connect(configDB.url);
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({ secret: 'shhsecret' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
require('./config/passport')(passport);
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
And here is my passport.js Im using local passport
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
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('local-signup', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true,
},
function(req, email, password, done) {
process.nextTick(function() {
User.findOne({ 'local.email': email }, function(err, user) {
if (err)
return done(err);
if (user) {
return done(null, false, req.flash('signupMessage', 'That email is already in use.'));
} else {
var newUser = new User();
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
passport.use('local-login', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true,
},
function(req, email, password, done) {
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', 'Wrong password.'));
return done(null, user);
});
}));
};
passport works it save the user to the database
expressauth 5 > db.users.find()
{ "_id" : ObjectId("586cc8b3ea780c071bbe2469"), "local" : { "password" : "$2a$08$vANw7GJIk8RUVEpJWnwSpOVQ77RuHCjbXiGoQVl.Fx/thhbMkEVWu", "email" : "david#david.com" }, "__v" : 0 }
expressauth 6 >
Cast to ObjectId failed for value “586cc8b3ea780c071bbe2469” at path “_id” for model “User”
I have built a couple apps that use passport oauth the exact same way that I have displayed above. So I dont know why Im getting this error.
Any suggestions?
I had the same problem with mongoose version > 4.7.2
Problem is about bson package.
I solved it with installing an older version of mongoose.
npm install mongoose#4.7.2
or you can change package.json to use exact version 4.7.2 "mongoose": "4.7.2"
You can update to newer versions after the problem is solved. You can track it on here.
The error exists in your serializeUser function in passport.
You need to use user._id instead of user.id.
since there is no field as id in your UserSchema, user.id will beundefined, and while deserializing the user, undefined is not typeOf ObjectId, thus it is throwing above error.
Try this:
passport.serializeUser(function(user, done) {
done(null, user._id);
});
Update:
Do this in your deserializeUser:
cast the upcoming id to ObjectId, just to be sure, and then use that ID to query the User.
var userId = mongoose.Schema.Types.ObjectId(id);
User.findById(userId , function(err, user) {
done(err, user);
});
Dont forget to include mongoose in the same file.
var mongoose=require('mongoose');
Hopefully this will help you.
This is due to latest version of mongoose, you have to use findOneAndRemove instead of FindByIdAndRemove.
That is cast objectId problem.
I have seen similar posts with this problem, but none of those answers seemed to fix my issue. Including the missing hyphen in a couple answers.
When I send the user to Twitter to get authenticated using Passport, the broswer says I have no GET handler for my callbackURL. I am super confused since I believe I do have it handled, but its not working.
In my app.js file I have:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var passport = require('passport');
var session = require('express-session');
app.set('views', './views');
app.set('view engine', 'jade');
app.use(express.static('public'));
app.use(express.static("node_modules/bootstrap/dist"));
app.use(express.static("node_modules/jquery/dist"));
app.use(express.static('img'));
app.use(require('express-session')({
secret:'prince', resave: false, saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
var authRouter = require('./admin/auth');
app.use("/admin/login", authRouter);
var frontPageFlow = require('./index');
app.get('/', frontPageFlow, function (req, res) {
res.render('index', {
title: "Crowd District"
});
});
In my Auth.js file I have:
var express = require('express');
var passport = require('passport');
var TwitterStrategy = require('passport-twitter').Strategy;
var router = express.Router();
module.exports = router;
router.get('/auth/twitter',
passport.authenticate('twitter'),
function (req, res) {
res.render('login')
});
router.get('/auth/twitter/callback',
passport.authenticate('twitter', {
successRedirect: '/',
failureRedirect: '/login'
}));
router.route('/')
.get(function (req, res) {
res.render("login");
})
.post(passport.authenticate('twitter', {
successRedirect: '/',
failureRedirect: '/admin/login'
})
);
passport.use(new TwitterStrategy({
consumerKey: 'Consumer key here',
consumerSecret: 'Consumer secret here',
callbackURL: 'http://localhost:9000/auth/twitter/callback'
},
function(token, tokenSecret, profile, cb) {
User.findOrCreate({ twitterId: profile.displayName }, function (err, user) {
if (err) { return cb(null, profile); }
if (!user){
user = new User ({
name: profile.displayName,
email: profile.emails[0].value,
username: profile.username,
provider: 'twitter'
});
user.save(function (err) {
if (err) console.log(err);
console.log("successful user entry!");
return done(err, user);
});
} else {
return done(err, user);
}
});
}
));
And my userModel.js
var mongoose = require('mongoose');
var express = require('express');
var router = express.Router();
module.exports = router;
var schemaOptions = {
collection: "users"
};
var schema = new mongoose.Schema({
id : String,
token : String,
displayName : String,
username : String
}, schemaOptions);
module.exports = mongoose.model('User', schema);
No matter what I do, or rearrange the order of operations, I continue to get in my callback:
Cannot GET /auth/twitter/callback?oauth_token=enfwejngfon2804&oauth_verifier=LK35h5988gieunrgbr4ghghi
Thank you very much in advance!
Your route paths are incorrect because you are using app.use("/admin/login", authRouter); which makes all routes in that file have a prefix '/admin/login', so instead of '/auth/twitter/callback', you code is expecting '/admin/login/auth/twitter/callback'. Get all your paths to line up and you'll be in better shape. I recommend avoiding mount prefixes when calling app.use. They just lead to this kind of confusion. Just use app.use(authRouter); and make your route paths absolute paths. They are much more straightforward to work with.