Passport Local Strategy returns not found - node.js

I'm trying to make a register/login with node, express and mongoose. I want to register and login users and if they aren't logged in they can't retrieve data from the api.
To make the login and register i have been watching this tutorial: Link it isn't as addecuate for my needs because half of the efforts and code goes into the ejs but i have been okay until the passport login.
I have created my local strategy in config/passport.js:
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcryptjs");
const User = require("../models/user");
module.exports = function (passport) {
passport.use(
new LocalStrategy({ usernameField: "email" }, (email, password, done) => {
User.findOne({ email: email })
.then((user) => {
if (!user) {
return done(null, false, {
message: "That email is not registered",
});
}
bcrypt.compare(password, user.password, (err, isMatch) => {
if (err) console.log(err);
if (isMatch) {
return done(null, user);
} else {
done(null, false, { message: "Incorrect Password" });
}
});
})
.catch((err) => console.log(err));
})
);
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});
};
My app.js looks like this:
const express = require("express");
const cors = require("cors");
const usersRouter = require("./routes/users");
const passport = require("passport");
const session = require("express-session");
require("dotenv").config();
const app = express();
require("./config/passport")(passport);
const connectDB = require("./db/connect");
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(
session({
secret: "*****",
resave: true,
saveUninitialized: true,
})
);
app.use(passport.initialize());
app.use(passport.session());
app.use(cors());
app.use("/api/v1/users", usersRouter);
const PORT = process.env.PORT || 5000;
const start = async () => {
try {
await connectDB(process.env.MONGO_URI);
app.listen(PORT, console.log(`Server is listening on port: ${PORT}....`));
} catch (error) {
console.log(error);
}
};
const notFound = require("./middleware/notFound");
app.use(notFound);
start();
My users router looks like this:
const express = require("express");
const router = express.Router();
const { postRegister } = require("../controllers/register");
router.route("/register").post(postRegister);
const { postLogin } = require("../controllers/login");
router.route("/login").post(postLogin);
module.exports = router;
The register works perfectly, but the login controller doesn't. Each time i post to that endpoint instead of getting a succesMessage or failureMessage i get the page not found router that is called at the end of app.js, i checked if the router calls the login function via a console log and it does. Here is the code for the login controller:
const passport = require("passport");
const postLogin = (req, res, next) => {
console.log("The function has been triggered");
passport.authenticate("local", {
successMessage: "Login authenticated",
failureMessage: "Login failed",
})(req, res, next);
};
module.exports = {
postLogin,
};
Why don't I get the responses from the login controller or my local strategy and instead i get page not found when the Login controller actually works?

Related

Passport.js authentication goes in infinite loop

I have been trying to build the authentication using PassportJs and MongoDB. I am using PassportJS only to log in. But, while submitting the post request it does not redirect me to the failureRedirect route, nor to the SuccessRedirect one, instead, the web page enters into an endless loop.
The code I have written is -
It has 2 files- app.js and user.js
App.js file -
const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const passport = require('passport');
const mongoose = require('mongoose');
require('./db/db')
var fileupload = require('express-fileupload');
const path = require('path');
const app = express();
app.use(fileupload({
useTempFiles: true
}));
const session = require('express-session');
const mongostore = require('connect-mongo');
app.use(express.static(path.join(__dirname,'public')));
// session middle ware
app.use(session({
secret : 'mysupersecret',
resave : false,
saveUninitialized : false,
store: mongostore.create({
mongoUrl: process.env.DB,
}),
cookie : { maxAge : 180 * 60 * 1000 }
}));
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static("public"));
app.use(bodyParser.json());
app.use(passport.initialize());
app.use(passport.session());
app.get("/", (req, res) => {
res.render("index");
});
app.use("/admin", require("./routes/admin"));
app.use("/user", require("./routes/user"));
app.use("/task", require("./routes/task"));
// PORT
const PORT = process.env.PORT || 5000;
app.listen(PORT, console.log(`Server started on port ${PORT}`));
User.js file -
const express = require("express");
const bodyParser = require("body-parser");
const router = express.Router();
const bcrypt = require("bcryptjs");
const passport = require("passport");
const User = require("../models/User");
const Task = require("../models/Task");
var LocalStrategy = require('passport-local');
// var bcrypt = require('bcryptjs');
var strategy = new LocalStrategy(function verify(email, password, done) {
try{
console.log(email);
User.findOne({email: email}, function (err, user) {
console.log(email);
if (err)
console.log(err);
if (!user) {
console.log("doen exist")
return done(null, false);
}
bcrypt.compare(password, user.password, function (err, isMatch) {
if (err)
console.log(err);
if (isMatch) {
return done(null, user);
} else {
console.log("galat password");
return done(null, false);
}
});
});
}catch(err){
console.log(err);
}
});
passport.use('epass',strategy);
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
// User login
router.get("/login", (req, res) => {
res.render("user-login");
});
router.post("/login", (req,res) => {
try{
passport.authenticate('epass', { failureRedirect: '/user/login' }),
function(req, res,next) {
res.redirect('/user');
}
}catch(err){
console.log(err);
}
});
router.get("/", (req, res) => {
res.render("user")
})
module.exports = router;
I have searched everywhere and tried all the available possible solutions but nothing is solving this.
passport.authenticate() should be used as a middleware, not as a regular function:
router.post("/login",
passport.authenticate('epass', { failureRedirect: '/user/login' }),
function(req, res,next) {
res.redirect('/user');
}
);
The way you were using it causes the request to POST /user/login to never finish, because it's not sending back any response.
EDIT: also, make sure that you either use the default field names of username and password for logging in, or add the relevant options to the constructor of LocalStrategy to tell it which fields it should be expecting.

Getting error TypeError: next is not a function

I'm getting error "TypeError: next is not a function" while trying to authenticate dashboard route in nodejs.
I am trying to make and CRUD app with node and mongoDB suing these modules express ejs mongoose bcryptjs passport passport-local.
Getting this error when I submit login form.
I am new in nodejs, Please help me
Thanks in advance.
auth/protect.js file
const protectRoute = (req, res, next) =>{
if (req.isAuthenticated()) {
return next();
}
console.log('Please log in to continue');
res.redirect('/login');
}
const allowIf = (req, res, next) =>{
if (!req.isAuthenticated()) {
return next();
}
res.redirect('/dashboard');
}
module.exports = {
protectRoute,
allowIf,
};
routes/login.js file
const express = require("express");
const {
registerView,
loginView,
registerUser,
loginUser,
} = require("../controllers/loginController");
const { dashboardView } = require("../controllers/dashboardController");
const { protectRoute } = require("../auth/protect");
const router = express.Router();
router.get("/register", registerView);
router.get("/login", loginView);
router.get("/", loginView);
//Dashboard
router.get("/dashboard", protectRoute, dashboardView);
router.post("/register", registerUser);
router.post("/login", loginUser);
module.exports = router;
server.js file
const express = require("express");
const cors = require("cors");
const app = express();
const mongoose = require('mongoose');
const session = require('express-session');
const passport = require("passport");
const { loginCheck } = require("./auth/passport");
var corsOptions = {
origin: "http://localhost:8081"
};
app.use(cors(corsOptions));
const db = require("./models");
db.mongoose
.connect(db.url, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log("Connected to the database!");
})
.catch(err => {
console.log("Cannot connect to the database!", err);
process.exit();
});
app.set('view engine', 'ejs');
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(session({
secret:'oneboy',
saveUninitialized: true,
resave: true
}));
app.use(passport.initialize());
app.use(passport.session());
// simple route
app.use('/', require('./routes/login'));
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
I have missed to call a function loginCheck(passport); in my server.js file that's why I was getting error during login form submission.
server.js starting code
const express = require("express");
const cors = require("cors");
const app = express();
const mongoose = require('mongoose');
const session = require('express-session');
const passport = require("passport");
//var LocalStrategy = require('passport-local').Strategy;
const { loginCheck } = require("./auth/passport");
loginCheck(passport);
........................................
I was added this function in auth/passport.js file
passport.js
//js
const bcrypt = require("bcryptjs");
LocalStrategy = require("passport-local").Strategy;
//Load model
const User = require("../models/User");
const loginCheck = passport => {
passport.use(
new LocalStrategy({ usernameField: "email" }, (email, password, done) => {
//Check customer
User.findOne({ email: email })
.then((user) => {
if (!user) {
console.log("wrong email");
return done();
}
//Match Password
bcrypt.compare(password, user.password, (error, isMatch) => {
if (error) throw error;
if (isMatch) {
return done(null, user);
} else {
console.log("Wrong password");
return done();
}
});
})
.catch((error) => console.log(error));
})
);
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (error, user) => {
done(error, user);
});
});
};
module.exports = {
loginCheck,
};
If you are trying to use next() in normal function then it will give an error
const allowIf = (req, res, next) =>{
return next(); // throw an error - TypeError: next is not a function
}
allowIf();
So use next() as a Callback argument to the middleware function. It will work fine in this case. Try this:
const protectRoute = (req, res, next) =>{
console.log('protectRoute');
return next();
}
app.get('/', protectRoute);

req.isAuthenticated() always return false and req.session.passport is undefined

I know that there are some questions like this already, but i already tried every single response and nothing works, i don't know what the heck to add to app.js to make it work and store the sessions.
Here is my app.js:
const express = require("express");
const cors = require("cors");
const usersRouter = require("./routes/users");
const passport = require("passport");
const cookieParser = require("cookie-parser");
const session = require("express-session");
require("dotenv").config();
const app = express();
const connectDB = require("./db/connect");
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser(process.env.SESSION_SECRET));
app.use(
session({
secret: process.env.SESSION_SECRET,
resave: true,
saveUninitialized: true,
cookie: { secure: false },
})
);
app.use(passport.initialize());
app.use(passport.session());
app.use(cors());
app.use("/api/v1/users", usersRouter);
const PORT = process.env.PORT || 5000;
const start = async () => {
try {
await connectDB(process.env.MONGO_URI);
app.listen(PORT, console.log(`Server is listening on port: ${PORT}....`));
} catch (error) {
console.log(error);
}
};
const notFound = require("./middleware/notFound");
app.use(notFound);
start();
My passport-config looks like this:
const localStrategy = require("passport-local").Strategy;
const bcrypt = require("bcryptjs");
const User = require("../models/user");
const initialize = (passport) => {
const authenticateUser = async (email, password, done) => {
let user = await User.findOne({ email: email });
User.findOne({ email: email });
if (!user) {
return done(null, false, {
message: "That email is not registered",
});
}
try {
if (await bcrypt.compare(password, user.password)) {
return done(null, user, { message: "User logged in" });
} else {
return done(null, false, { message: "Password incorrect" });
}
} catch (e) {
return done(e);
}
};
passport.use(new localStrategy({ usernameField: "email" }, authenticateUser));
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (user, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
};
module.exports = initialize;
And my users router looks like this:
const express = require("express");
const router = express.Router();
const passport = require("passport");
const initializePassport = require("../config/passport-config");
initializePassport(passport);
const { postRegister } = require("../controllers/register");
router.route("/register").post(postRegister);
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({ message: info.message });
}
console.log(req.session.passport);
res.status(200).json(user);
})(req, res, next);
});
module.exports = router;
I'm making a middleware to authorize or to not authorize the call to another endpoint based on if it is authenticated or if it isn't.
Here is how that middleware looks:
const checkAuthenticated = (req, res, next) => {
const isAuthenticated = req.isAuthenticated();
console.log(req.session.passport);
if (isAuthenticated) {
next();
}
next();
};
module.exports = checkAuthenticated;
const checkNotAuthenticated = (req, res, next) => {
const isAuthenticated = req.isAuthenticated();
if (!isAuthenticated) {
res
.status(401)
.json({ msg: "Not allowed to this path without credentials" });
}
};
module.exports = checkNotAuthenticated;
req.session.passport is undefined, isAuthenticated() is always false, i don't know what to add.
Your bug in the deserializer function:
It will work by changing your deserializer callback argument from user to id as shown below.
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
That was a very obvious bug to me, to be sure you are not missing any other thing, check the lengthy answer I gave to this on another thread a few minutes ago here: https://github.com/jaredhanson/passport/issues/914#issuecomment-1241921637
Good luck.

successRedirect is not working in passport login passport-local

I am using node.js express with sequelize and database postgreSql.the problem is in passport login failureRedirect works properly sucessRedirect does not redirect to the page that I want. It still loading and not responding anything and does not come any error.
when I submit login it will check for errors if errors it will work perfectly in failureRedirect but in Success it does not work like page has loading only not goes to the destination page and if I stop the project and restart the project it will be in destination page!! i dont know what is the problem help me.
mainController.js
const express = require("express");
const sessions = require("express-session");
require("../model/MasterUser.model");
const passport = require("passport");
var session = sessions;
const router = express.Router();
router.get("/dashboard", (req, res) => {
res.render('dashboard');
});
router.get("/login", (req, res) => {
res.render("login", { layout: "login.hbs" });
});
router.post(
"/login",
passport.authenticate("local", {
successRedirect: "/main/dashboard",
failureRedirect: "/main/login",
failureFlash: true,
})
);
module.exports = router;
passport.js
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcryptjs");
const sequelize = require("sequelize");
const masterUser = require("../model/MasterUser.model");
module.exports = function (passport) {
passport.use(
new LocalStrategy(
{ usernameField: "user_name" },
(user_name, password, done) => {
// Match user
masterUser.findOne({ where: { user_name: user_name } }).then((user) => {
if (!user) {
return done(null, false, {
message: "This username is 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" });
}
});
});
}
)
);
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
masterUser.findByPk(id, (err, user) => {
done(err, user);
});
});
};
index.js
const express = require("express");
const Handlebars = require("handlebars");
var flash = require("connect-flash");
const app = express();
const path = require("path");
const bodyparser = require("body-parser");
const expressHandlebars = require("express-handlebars");
const passport = require("passport");
const sessions = require("express-session");
var session = sessions;
const MainController = require("./controllers/MainController");
const db = require("./config/database");
//test db
db.authenticate()
.then(() => console.log("Database Connected..."))
.catch((err) => console.log("error" + err));
//for security purpose
const cors = require("cors");
app.use(
cors()
);
//Passport Config
require("./config/passport")(passport);
app.use(cookieParser());
//use body parser
app.use(bodyparser.json());
app.use(bodyparser.urlencoded({ extended: true }));
const {
allowInsecurePrototypeAccess,
} = require("#handlebars/allow-prototype-access");
app.use(
bodyparser.urlencoded({
urlencoded: true,
})
);
app.use(
sessions({
secret: "secret_key",
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60000 },
})
);
// use flash for show messages
app.use(flash());
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
//flash messages
app.use((req, res, next) => {
res.locals.success_msg = req.flash("success_msg");
res.locals.error_msg = req.flash("error_msg");
res.locals.error = req.flash("error");
next();
});
//setting up view Engine
app.set("views", path.join(__dirname, "/views"));
//using the hbs
app.engine(
"hbs",
expressHandlebars({
extname: "hbs",
defaultLayout: "default",
layoutsDir: __dirname + "/views/layouts",
handlebars: allowInsecurePrototypeAccess(Handlebars),
})
);
app.set("view engine", "hbs");
//route for Main
app.use("/main", MainController);
//default
app.get("/", (req, res) => {
res.render("login");
});
app.listen(3000, () => {
console.log("App listening on port 3000!");
});
the problem has been solved guys I made done wrong code in deserializeUser.
passport.js before
passport.deserializeUser((id, done) => {
masterUser.findByPk(id, (err, user) => {
done(err, user);
});
});
};
passport.js after
passport.deserializeUser(function (id, done) {
masterUser.findOne({ where: { id: id } }).then((user) => {
done(null, user);
});
});
the problem is for sequelize get the user data is different so now its worked for me.this is useful for who using express with sequelize and passport with postgresql

JWT login issue

I'm using JWT with Passport for authentication in my app. I use MongoDB and Mongoose for database. I added a user with username = manager and password=manager with addManager function the password saved in db is not "manager" and is : "$2b$10$O7YAgTJKETOY.lanZoErWum2e6ZPpVi.RjMp0VHKfMT82z9uEmrlS" I don't know why! and I can't login with password :"manager". I don't know what is the problem .I used this article for my code. if you understand what't wrong please tell me.
app.js :
//settings and Requirements
const express = require('express');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const path = require('path');
const mongoose = require('mongoose');
const passport = require('passport');
const config = require('./api/config/database');
mongoose.connect(config.database);
let db = mongoose.connection;
require('./api/config/auth');
db.once('open', function () {
console.log('connected to mongodb...');
});
db.on('error', function (error) {
console.log(error);
});
let User = require('./api/models/user');
let basics = require('./api/config/basics');
let port = process.env.PORT || 8080;
const app = express();
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json());
app.use(bodyParser.json({
type: 'application/vnd/api+json'
}));
app.use(cookieParser());
basics.addManager(basics.manager);
router(app);
app.listen(port, function (err) {
if(err)
console.log(err);
console.log("port is " + port);
});
auth.js:
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const User = require('../../api/models/user');
const passportJWT = require("passport-jwt");
const JWTStrategy = passportJWT.Strategy;
const ExtractJWT = passportJWT.ExtractJwt;
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
},
function (username, password, cb) {
//this one is typically a DB call. Assume that the returned user object is pre-formatted and ready for storing in JWT
return User.findOne({username:username, password:password})
.then(user => {
if (!user) {
return cb(null, false, {message: 'Incorrect username or password.'});
}
return cb(null, user, {message: 'Logged In Successfully'});
})
.catch(err => cb(err));
}
));
passport.use(new JWTStrategy({
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
secretOrKey : 'your_jwt_secret'
},
function (jwtPayload, cb) {
//find the user in db if needed. This functionality may be omitted if you store everything you'll need in JWT payload.
return User.findOneById(jwtPayload.id)
.then(user => {
return cb(null, user);
})
.catch(err => {
return cb(err);
});
}
));
authenticate.js:
const express = require('express');
const passport = require('passport');
const jwt = require('jsonwebtoken');
const router = express.Router();
router.post('/login', function (req, res, next) {
console.log(req.body);
passport.authenticate('local', {session: false}, (err, user, info) => {
console.log(user);
if (err || !user) {
return res.status(400).json({
message: info ? info.message : 'Login failed',
user : user
});
}
req.login(user, {session: false}, (err) => {
if (err) {
res.send(err);
}
// generate a signed son web token with the contents of user object and return it in the response
const token = jwt.sign(user, 'your_jwt_secret');
return res.json({user, token});
});
})(req, res);
});
module.exports = router;
addManager:
`
addManager : function(manager){
let newUser = new User({
username : manager.username,
password : manager.password,
isManager : true
});
newUser.save(function(err , user){
if(err)
console.log(err);
console.log('manager added successfuly');
});
}
`

Resources