I am using passport local for authentication and the login credentials don't get authenticated. I just get redirected to the failureRedirect. I don't even get the flash error.
Here is my login route:
var express = require('express');
var router = express.Router();
var passport = require('passport');
var flash = require('connect-flash');
router.get('/', function(req, res, next) {
if(req.user){
return res.redirect('/profile');
}
var vm = {
title: 'Login',
error: req.flash('error')
};
res.render('login', { title: 'Place an order' });
});
router.post('/',
passport.authenticate('local', {
failureRedirect: '/login',
successRedirect: '/profile',
failureFlash: 'Invalid credentials'
}));
module.exports = router;
This is app.js:
var express = require('express');
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var passport = require('passport');
var expressSession = require('express-session');
var flash = require('connect-flash');
var config = require('./config');
var routes = require('./routes/index');
var signup = require('./routes/signup');
var login = require('./routes/login');
var profile = require('./routes/profile');
var restrict = require('./auth/restrict');
var passportConfig = require('./auth/passport-config');
passportConfig();
mongoose.connect(config.mongoUri);
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
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(expressSession({
secret: 'themsec',
saveUninitialized: false,
resave: false
}));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
app.use('/', routes);
app.use('/signup', signup);
app.use('/login', login);
//app.use(restrict);
app.use('/profile', profile);
// 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;
Passport-config:
module.exports = function(){
var passport = require('passport');
var passportLocal = require('passport-local');
var userService = require('../services/user-service');
passport.use(new passportLocal.Strategy({username: 'email'},function(email, password, next){
userService.findUser(email, function(err, user){
if(err){
return next(err);
}
if(!user || user.password!= password){
return next(null, null);
}
next(null, user);
});
}));
passport.serializeUser(function(user, next){
next(null, user.email);
});
passport.deserializeUser(function(email, next){
userService.findUser(email, function(err, user){
next(err, user);
});
});
};
User services:
var User = require('../models/user').User;
exports.addUser = function(user, next){
var newUser = new User({
firstName: user.firstName,
lastName: user.lastName,
email:user.email.toLowerCase(),
password: user.password,
});
newUser.save(function(err){
if(err)
return next(err)
next(null);
});
};
exports.findUser = function(email, next){
User.findOne({email:email.toLowerCase()}, function(err, user){
next(err, user)
});
};
User model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userService = require('../services/user-service');
var userSchema = new Schema({
firstName: {type: String, required: true},
lastName: String,
email: {type: String, required: true},
password: {type: String, required: true},
created: {type: Date, default: Date.now}
});
userSchema.path('email').validate(function(value, next){
userService.findUser(value, function(err, user){
if(err){
console.log(err);
return false;
}
next(!user)
});
}, 'That email is already in use');
var User = mongoose.model('User', userSchema);
module.exports = {
User:User
};
Someone please help me, I am turning mad with frustration. I am new to Node.
Edit: I have removed the code that would lead to an infinite loop if the user logged-in, however, I still cannot login.
Related
I'm creating a MEAN Stack food catalog application. Node.js gives me the user logged in, in my login route when I check for req.isAuthenticated(). But when I try to check later whether I'm still logged in, it gives req.user as undefined.
How do I make the user persist? I know I can use local storage but is there a better way?
var express = require('express');
var cors = require('cors');
var bodyParser = require('body-parser');
var passport = require('passport');
var mongoose = require('mongoose');
var LocalStrategy = require('passport-local');
var passportLocalMongoose = require('passport-local-mongoose');
app = express();
app.use(require('express-session')({secret:"timelord",resave:false,saveUninitialized:false}));
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(passport.initialize());
app.use(passport.session());
mongoose.set('useNewUrlParser', true);
mongoose.set('useUnifiedTopology', true);
mongoose.connect('mongodb://127.0.0.1:27017/delectabledb');
var UserSchema = new mongoose.Schema({name: String,
gender: String,
dob: String,
country:String,
phone: String,
email: String,
password: String,
username: String,
prof: String});
UserSchema.plugin(passportLocalMongoose);
var User = mongoose.model("User", UserSchema);
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.post('/loginUser', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
console.log(req.user) //returns false
if (err) { return next(err); }
if (!user) { res.send({code:"500"}); }
req.logIn(user, function(err) {
console.log(req.user) //returns true
if (err) { return next(err); }
res.send({code:"200", user:user});
});
})(req, res, next);
});
app.listen(3000, ()=>{
console.log("Running server on port 3000...");
});
I'm trying to create a schema for a user authentication system but keep getting the above error message. I've created two new pages with the following code:
Users.js
var mongoose = require ('mongoose');
var crypto = require ('crypto');
var jwt = require('jsonwebtoken');
var userSchema = new mongoose.Schema({
email:{
type: String,
unique: true,
required: true
},
name: {
type: String,
required: true
},
hash: String,
salt: String
});
userSchema.methods.setPassword = function(password){
this.salt = crypto.randomBytes(16).toString('hex');
this.hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64).toString('hex');
};
//when the setPassword method is called and supplied with a password, the salt and hash will be generated
//for users and added to the model instance - password is never saved anywhere, and not even stored in memory
userSchema.methods.validPassword = function(password){
var hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64).toString('hex');
return this.hash === hash;
};
userSchema.methods.generateJwt = function(){
var expiry = new Date();
expiry.setDate(expiry.getDate() + 7);
return jwt.sign({
_id: this._id,
email: this.email,
name: this.name,
exp: parseInt(expiry.getTime() / 1000),
}, process.env.JWT_SECRET);
};
/*var User = mongoose.model('user');
var user = new User();
user.name = "User's name";
user.email = "test#example.com";
user.setPassword("myPassword");
user.save();*/
authentication.js
var passport = require('passport');
var mongoose = require('mongoose');
var User = mongoose.model('User');
var sendJSONreponse = function(res, status, content) {
res.status(status);
res.json(content);
};
//register controller for the API
module.exports.register = function(req, res){
if(!req.body.name || !req.body.email || !req.body.password){
sendJSONreponse(res, 400, {
"message": "All fields required"
});
return;
}
var user = new User();
user.name = req.body.name;
user.email = req.body.email;
user.setPassword(req.body.password);
user.save(function(err) {
var token;
if (err){
sendJSONreponse(res, 404, err);
} else{
token = user.generateJwt();
sendJSONreponse(res, 200, {
"token" : token
});
}
});
};
//Login controller for the API
module.exports.login = function(req, res) {
if(!req.body.email || !req.body.password){
sendJSONreponse (res, 400, {
"message" : "All fields required"
});
return;
}
passport.authenticate('local', function(err, user, info){
var token;
if (err){
sendJSONreponse(res, 404, err);
return;
}
if(user){
token = user.generateJwt();
sendJSONreponse(res, 200, {
"token" : token
});
} else {
sendJSONreponse(res, 401, info);
}
}) (req, res);
};
module.exports = router;
app.js This is some of the code which relates to the above
require('dotenv');
var express = require('express');
var createError = require('http-errors');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var bodyParser = require('body-parser');
var uglifyJS = require("uglify-js");
var fs = require ('fs');
var passport = require('passport');
//require('./app_api/models/blogModel');
require('./app_api/models/db');
require('./app_api/config/passport');
var routesApi = require('./app_api/routes/index');
var mongoose = require("mongoose");
var mongoDB = "mongodb://**********************************;
mongoose.Promise = global.Promise;
mongoose.connect(mongoDB, {useNewUrlParser: true, useUnifiedTopology: true})
.then(() => console.log('connection successful'))
.catch((err) => console.log(err));
/*BRING IN SCHEMAS AND MODELS*/
require('./users');
var app = express();
app.use(bodyParser.json());
app.use(express.static('public'));
app.use(bodyParser.urlencoded({
extended: true
}));
// view engine setup
app.set('views', path.join(__dirname, 'app_server', 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'app_client')));
app.use(passport.initialize());
app.use('/api', routesApi);
//make db accessible to router
// app.use(function(req, res, next){
// req.db=db;
// next();
// });
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
// catch unauthorised errors
app.use(function (err, req, res, next){
if (err.name === 'UnauthorizedError'){
res.status(401);
res.json({"message" : err.name + ": " + err.message});
}
});
module.exports = app;
I've been following a textbook and the formatting etc. is correct; I just don't know where the error is coming from.
Thank you in advance!
At the bottom of Users you need to declare the model, using mongoose.model('Users',userSchema); also export it, you then interact with the model, schema is more of a declaration (details), the model is the implementation providing the functionality you're requiring.
You actually were pretty close, you needed to add the schema argument to the model.
I am trying to generate token while logging in locally. Let's say I am normal user and want to sign in. Will token get generated while signing in? and how? Need guidance. Thanks
As I am using mongodb I require my users schema model in my routes code.Here is my routes code user.js
var express = require('express');
var router = express.Router();
var passport = require('passport');
var User = require('../models/schema');
var Verify = require('./verify');
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.post('/register', function(req, res) {
User.register(new User({ username : req.body.username,email: req.body.email, phone:req.body.phone }),req.body.password,
function(err, user) {
if (err) {
return res.status(500).json({err: err});
}
passport.authenticate('local')(req, res, function () {
return res.status(200).json({status: 'Registration Successful!'});
});
});
});
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).json({
err: info
});
}
req.logIn(user, function(err) {
if (err) {
return res.status(500).json({
err: 'Could not log in user'
});
}
var token = Verify.getToken(user);
res.status(200).json({
status: 'Login successful!',
success: true,
token: token
});
});
})(req,res,next);
});
router.get('/logout', function(req, res) {
req.logout();
res.status(200).json({
status: 'Bye!'
});
});
module.exports = router;
When you look at the code you will notice a verify variable.It is nothing but verification that is user is registered or not.If user registered then user will allow for login.After login user will get a successfull response along with token.So here is my veirfy code verify.js
var User=require('../models/schema');
var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
var config = require('../config.js');
exports.getToken = function (user) {
return jwt.sign(user, config.secretKey, {
expiresIn: 3600
});
};
exports.verifyOrdinaryUser = function (req, res, next) {
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, config.secretKey, function (err, decoded) {
if (err) {
var err = new Error('You are not authenticated!');
err.status = 401;
return next(err);
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
var err = new Error('No token provided!');
err.status = 403;
return next(err);
}
};
If you observe the code there is a variable like config this is nothing but connection to my mongodb.Here is the code config.js
module.exports = {
'secretKey': '12345-67890-09876-54321',
'mongoUrl' : 'mongodb://localhost:27017/conFusion'
}
And the user schema is here schema.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
var User= new Schema({
username:{
type:String,
required:true,
unique:true
},
email:{
type:String,
required:true,
unique:true
},
phone:{
type:Number,
required:true,
unique:true
},
password:{
type:String
}
});
User.plugin(passportLocalMongoose);
module.exports = mongoose.model('User',User);
And finally server code 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 mongoose = require('mongoose');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var config = require('./config');
mongoose.connect(config.mongoUrl);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
console.log("Connected correctly to server");
});
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// 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')));
var User = require('./models/schema');
app.use(passport.initialize());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
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 handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.listen(3000,function(){
console.log("Server Listening on 3000");
});
module.exports = app;
project structure must be as per my code
+app.js
+config.js
+routes(directory)
++user.js
++verify.js
+models(directory)
++schema.js
run the code node app.js
When you want to register use http://localhost:3000/users/register
and for login use http://localhost:3000/users/login
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've a issue with PassportJS. It displays this message and I can't understand where I'm doing wrong:
{"message":"Unknown authentication strategy \"facebook\"","error":{}}
GET /auth/facebook 500 0.505 ms - 69
Credentials are hardcoded for simplicity and learning purpose. Passport and Passport-Facebook are installed.
auth/index.js
var passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;
var User = require('../modules/user');
module.exports = function(){
passport.use( new FacebookStrategy({
clientID: "secret",
clientSecret : "secret",
callbackURL : "secret"
},
function(accessToken, refreshToken, profile, done) {
User.findOne({ email: profile.emails[0].value }, function (err, user) {
if (err) { return done(err) }
if (!user) {
user = new User({
firstname: profile.name.givenName,
lastname: profile.name.familyName,
email: profile.emails[0].value,
providers: {
facebook: {
id: profile.id,
access_token: accessTOken,
display_name: displayName,
picture: "http://graph.facebook.com/"+profile.id+"/picture?type=square"
}
}
})
user.save(function (err) {
if (err) console.log(err)
return done(err, user)
})
}
else {
return done(err, user)
}
})
}
));
};
routes/auth.js
var express = require('express');
var router = express.Router();
var passport = require('passport');
router.get('/facebook', passport.authenticate('facebook'), function(res, res){});
router.get('/facebook/callback', passport.authenticate('facebook'), function(res, res){});
module.exports = router;
app.js
const express = require('express');
const path = require('path');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const passport = require('passport');
const auth = require('./routes/auth');
const app = express();
mongoose.connect('mongodb://localhost:auth/auth');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(passport.initialize());
app.use('/auth', auth);
// 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.json({
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.json({
message: err.message,
error: {}
});
});
module.exports = app;
SOLUTION:
As suggested, I just add this line before app.use(passport.initialize());
app.js
require('./auth')(passport);
SOLUTION:
As suggested, I just add this line before app.use(passport.initialize());
app.js
require('./auth')(passport);