Why wont passport.authenticate do anything despite it seeming to have no errors - node.js

I am writing an Express app using Passport and PostgreSQL for account creation and login.
All of the database parts are working fine but when it gets to passport.authenticate nothing seems to happen.
I've tried modifying my code to better match examples I found online but haven't been able to get anything back from any of the print statements.
Here's some of the code from my index.js file:
const express = require("express");
const bodyParser = require("body-parser");
const session = require("express-session");
const { response } = require("express");
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcrypt");
const db = require("./dbManager.js")
const app = express();
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(express.static(__dirname + "/Public"));
app.use(session({
secret: "example",
saveUninitialized: true,
resave: true
}));
app.use(passport.initialize());
app.use(passport.session());
//Uses pasport to authenticate user
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
}, function (email, password, done) {
console.log("Logging in ", email);
//This sends the query to the db
db.findUser(email).then(function (row) {
if (!row) {
return done(null, false, "Sorry that user doesn't exist");
} else {
//This compairs the passwords
bcrypt.compare(password, row.password, function (ex, result) {
//Checks if they match
if (result == true) {
//Sets up user
done(null, row.id);
} else {
return done(ex, false, "Incorrect password");
}
})
}
}).catch(function (ex) {
console.error(ex);
return done(ex, false);
});
}));
passport.serializeUser(function (user, done) {
console.log(user, done);
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
db.deserializeUser(id).then(function (row) {
console.log("User found id is:", row.id);
done(null, row.id)
}).catch(function (ex) {
console.error(ex);
})
});
app.listen(3000, function () {
console.log('Server running on port 3000');
});
app.get("/createAccount", function (req, res) {
res.sendFile(__dirname + "/Public/Create Account/createAccount.html");
});
app.post("/createAccount", function (req, res) {
const email = req.body.email;
const password = req.body.password;
bcrypt.hash(password, 10, function (ex, hashedPassword) {
if (ex != null) {
console.log(ex);
}
db.addUser(email, hashedPassword).then(function () {
console.log("New user added");
res.status(204).send("user added");
}).catch(function (ex) {
console.error(ex);
res.status(403).send(ex);
});
});
});
app.get("/logIn", function (req, res) {
res.sendFile(__dirname + "/public/Log In/login.html");
});
app.post("/logIn", function (req, res) {
console.log("Logging user in");
passport.authenticate("local", function (ex, user, info) {
console.log("Authentication");
if (ex) {
console.error(ex);
res.status(403).send(ex);
} else if (!user) {
console.log(info);
res.status(400).send(info);
} else {
req.logIn(user, function (ex) {
if (ex) {
console.error(ex);
res.status(400).send(ex);
} else {
console.log("User now authenticated");
res.status(200).send("Success");
}
})
}
});
});
Here is code from my createAccount.js script:
//This will run when the form is submitted
$("#submitBtn").click(function() {
//prepares data to be sent
body= {
email:$("#email")[0].value,
password:$("#password")[0].value
};
//This sends the post request to the server
$.post("/createAccount",body).done(accountCreated(body)).fail(accountNotCreated);
});
function accountCreated(body) {
console.log("User Added");
console.log(body.email);
//Sends post request to log user in
$.post("/logIn",body).done(function() {
console.log("You are now logged in");
window.location.replace("/");
}).fail(function(ex) {
console.error(ex);
});
}
function accountNotCreated(ex) {
console.error(ex);
}
The log output for this is as follows:
Logging user in
New user added
I'm not sure why this is in the wrong order either.

The problem here is that you are running the accountCreated function before you make the post to /createAccount. This line is the culprit
$.post("/createAccount",body).done(accountCreated(body)).fail(accountNotCreated);
This line of code is supposed to be setting up the accountCreated function to run after the call to $.post finishes successfully. However, because you're including the brackets after the function it's executing the function immediately and using whatever is returned as the handler for when they post completes.
You can fix this by wrapping the call to accountCreated in an anonymous function.
$.post("/createAccount",body).done(function() {
accountCreated(body)
}).fail(accountNotCreated);
I hope that helps.

Related

Node.js passport doesn't redirect on failureRedirect

So I'm trying to make a node.js project with passport authentification. When I log in with correct credentials, login works perfectly. But if I try to log in with wrong password and correct email, instead of redirecting back to login page, the site just keeps on loading indefinetly.
Here is my server.js code:
require('dotenv').config();
const express = require('express');
const app = express();
const passport = require('passport');
const initializePassport = require('./passport-config');
const session = require('express-session');
const methodOverride = require('method-override');
initializePassport(
passport,
async email=>{
try{
let bookshelfUser = await createBookshelfOf("User");
return await new bookshelfUser().where("email", email).fetch().then((data)=>{
return data.attributes;
});
}
catch (e) {
console.log(e);
return null;
}},
async id=>{
try{
let bookshelfUser = await createBookshelfOf("User");
return await new bookshelfUser().where("id", id).fetch().then((data)=>{
return data.attributes;
});
}
catch (e) {
return null;
}});
app.post('/login', passport.authenticate('local', {
successRedirect : '/',
failureRedirect : '/login',
})
);
And this is passport-config
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt');
function initialize(passport, getUserByEmail, getUserById) {
console.log("Passport initialized");
const authenticateUser = async (email, password, done) => {
const user = await getUserByEmail(email);
if (user == null) {
console.log("No user with that email");
return done(null, false, { message: 'No user with that email' });
}
try {
await bcrypt.compare(password, user.geslo, (err, result)=>{
if (err){
console.log("Password incorrect");
return done(null, false, { message: 'Password incorrect' });
}
if(result){
console.log("User logged in successfully: " + user.username);
return done(null, user);
}
});
} catch (e) {
console.log(e);
return done(e)
}
}
passport.use(new LocalStrategy({ usernameField: 'email' }, authenticateUser));
passport.serializeUser((user, done) => done(null, user.id));
passport.deserializeUser(async(id, done) => {
return done(null, await getUserById(id));
})
}
module.exports = initialize
I see two possible issues:
you're mixing promises with callbacks for bcrypt.compare(), which may not work (but perhaps it might, I don't know bcrypt too well);
it's not an error when a password doesn't match a hash for bcrypt.compare(); instead, result will be false, and you're not handling that case.
Here's a rewritten version of the block:
try {
const result = await bcrypt.compare(password, user.geslo);
if (! result) {
console.log("Password incorrect");
return done(null, false, { message: 'Password incorrect' });
} else {
console.log("User logged in successfully: " + user.username);
return done(null, user);
}
} catch (e) {
console.log(e);
return done(e)
}

400 Bad Request in NodeJs Application

When ever I submit a from to login in or get registered I get 400 bad request. But in register route the user get registered but it also gives bad request. When we go to login route same as register route I get BAD REQUEST. 0
I am using the following dependencies:
express session
passport
passport-local
passport-local-mongoose
Is there something wrong with the implementation of the passport-local-mongoose or its passport side or serialize or deserialize the user. Can anybody help me with this problem I am stuck on this for three days. Here is some code.
//-----------------------//Require---------------------
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const ejs = require("ejs");
const session = require("express-session");
const passport = require("passport");
const LocalStrategy= require("passport-local").Strategy;
const passportLocalMongoose = require("passport-local-mongoose");
const mongoose = require("mongoose");
//-----------------------//App.use---------------------
app.use(express.static("public"));
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({extended: true}));
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}));
//-----------------------//Passport---------------------
app.use(passport.initialize());
app.use(passport.session());
//-----------------------//Mongoose---------------------
mongoose.connect('mongodb://localhost/Twitter', {useNewUrlParser: true, useUnifiedTopology: true});
mongoose.set('useCreateIndex', true);
const tweetschema = new mongoose.Schema({
username: String,
password: String,
tweets: String
});
//-----------------------//Schema Plgin---------------------
tweetschema.plugin(passportLocalMongoose);
//-----------------------//New Model---------------------
const Tweet = new mongoose.model("Tweet", tweetschema);
//-----------------------//Local Strategy-------------------
passport.use(new LocalStrategy(Tweet.authenticate()));
//-----------------------//Seralize Passport---------------------
passport.serializeUser(Tweet.serializeUser());
passport.deserializeUser(Tweet.deserializeUser());
//-----------------------//Get Routes---------------------
app.get("/" ,(req, res)=>{
Tweet.find({}, function(err, founItems){
res.render("home", {founItems:founItems});
});
});
app.get("/tweets", (req, res)=>{
if(req.isAuthenticated()){
res.render("Tweets");
}else{
res.redirect("/login");
}
});
//-----------------------//Post Routes---------------------
app.post("/login", (req, res)=>{
const user = new Tweet({
username: req.body.email,
password: req.body.password
});
req.logIn(user, (err)=>{
if(err){
res.send(err);
}
passport.authenticate("local")(req, res, ()=>{
console.log("Successfull.");
})
})
});
app.post("/reg", (req, res)=>{
Tweet.register({username: req.body.email}, req.body.password, (err, user)=>{
if(err){
console.log(err);
res.redirect("/reg");
}else{
if(user){
passport.authenticate("local")(req, res, ()=>{
res.redirect("/tweets");
console.log("Successfully Regsitered The User!");
})
}
}
})
})
You redirect user to /login route, but you don't have get request for this.
If you have it but not uploaded try this in Seralize Passport
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
What about this:
app.post("/login", (req, res) => {
const email = req.body.email;
User.findOne({ username: email }, function (err, u) {
if (err) {
console.log(err);
} else {
if (u) {
u.authenticate(req.body.password, (err, model, info) => {
if (info) {
res.send("Wrong email or password!");
}
if (err) {
console.log(err);
} else if (model) {
req.login(u, (err) => {
if (err) {
console.log(err);
} else {
passport.authenticate("local");
req.session.save((error) => {
if (err) {
console.log(err);
} else {
res.redirect("/");
}
});
}
});
}
});
} else {
res.send("Wrong email or password!");
}
}
});
});
So you first search user in the database with email: User.findOne({ username: email }, function (err, u){} I suggest to make username unique username: { type: String, unique: true} in tweetSchema.
After that you check for err. If u exists, you authenticate it with password. According to passport-local-mongoose- u.authenticate(password, (err, model, info)=>{}) has two arguments: password and callback function. In callback we check for info which is "an instance of AuthenticationError describing the reason the password failed, else undefined." After that we check for err and it is "null unless the hashing algorithm throws an error." And finally, we check for model that is "the model getting authenticated if authentication was successful otherwise false."
So, model is authenticated. After that we must use the user with req.login(u,(err)). Check for errors and if everything is alright, we authenticate user locally passport.authenticate("local");. If you want to save session, write:
req.session.save((error) => {
if (err) {
console.log(err);
} else {
res.redirect("/");
}
});
That's all.
For registration :
app.post("/register", (req, res) => {
const email = req.body.email;
const password = req.body.password
User.find({ email: email }, function (err, docs) {
if (docs.length === 0) {
User.register(
{
username: email,
},
password,
function (err, user) {
if (err) {
console.log(err);
} else {
req.login(user, (err) => {
if (err) {
console.log(err);
} else {
passport.authenticate("local");
req.session.save((error) => {
if (err) {
console.log(err);
} else {
res.redirect("/");
}
});
}
});
}
}
);
} else {
res.send("The accout already exists!");
}
});
});

passport.deserializeUser() not being called and req.user is undefined

Alright, I've been racking my brain over this for hours now. When I call my 'sign-in' route the passport middleware works fine and returns with a req.user obj, but when I call another route after that, req.user for that other route is undefined. Where exactly have I messed up here? I'm not sure it matters, but I am calling my API routes from a react client.
auth
router.post(
"/sign-in",
passport.authenticate("local"),
async (req, res, next) => {
if (!req.user) console.log("NO USER!*******************");
try {
const user = _.get(req, "user", "");
res.status(200).json(user);
} catch (e) {
console.log({ e });
return res.status(400).json(false);
}
}
);
My Server
app.use(cors());
app.use(cookieparser());
app.use(logger("dev"));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(
session({
secret: "super",
resave: false,
saveUninitialized: true,
cookie: { secure: false, maxAge: 4 * 60 * 60 * 1000 }
})
);
require("./utils/passport");
app.use(passport.initialize());
app.use(passport.session());
./utils/passport
const _ = require("lodash");
const LocalStrategy = require("passport-local").Strategy;
const { PrismaClient } = require("#prisma/client");
const prisma = new PrismaClient();
const bcrypt = require("bcrypt");
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(async function(id, done) {
console.log("");
console.log("deserializeUser*************************");
console.log("");
try {
const user = await prisma.user.findOne({ where: { id } });
if (!user) {
return done(null, false);
}
return done(null, user);
} catch (e) {
done(e);
}
});
passport.use(
new LocalStrategy(
{
passReqToCallback: true,
usernameField: "email"
},
async (req, email, password, done) => {
try {
const user = await prisma.user.findOne({ where: { email } });
if (!user) {
return done(null, false);
}
await bcrypt.compare(
password,
_.get(user, "password", ""),
(err, result) => {
if (!result) {
done(null, false);
}
done(null, user);
}
);
} catch (e) {
done(e);
}
}
)
);
I suspect something is wrong with the portion where you have your post method with passport authenticate.
This portion may be deleted:
if (!req.user) console.log("NO USER!*******************");
I think the asynchronous may produce here odd results. Then for the sake of troubleshooting, include in your
const user = _.get(req, "user", "");
real data, such as real user data. Thus you will be able to verify that the data is passing through.

Passport + Express - User Sessions Conflicting

I have a simple Node+Express application with Passport Local authentication, it's working nearly perfectly (the right pages are served up, login/logout works, etc).
One issue though is that if a second user logs in, that session "takes over" the first user's session and suddenly the first user is now logged in as the second user!
This is almost certainly an issue with the order of the middleware, but I haven't been able to find it - I'm fairly new to Passport and Express. The code is taken liberally from docs and examples, but I might have messed the order up.
I've followed the order in this answer but it's still not working. Can anyone suggest where I might be mixed up?
The main server:
var express = require('express');
var passport = require('passport');
var Strategy = require('passport-local').Strategy;
var url = require('url');
var db = require('./db');
// Configure the local strategy for use by Passport.
passport.use(new Strategy(
function(username, password, cb) {
db.users.findByUsername(username, function(err, user) {
if (err) { return cb(err); }
if (!user) { return cb(null, false); }
if (user.password != password) { return cb(null, false); }
return cb(null, user);
});
}));
// Configure Passport authenticated session persistence.
passport.serializeUser(function(user, cb) {
console.log('DEBUG: serializeUser called ' + user.id);
cb(null, user.id);
});
passport.deserializeUser(function(id, cb) {
console.log('DEBUG: deserializeUser called ' + id);
db.users.findById(id, function (err, user) {
if (err) { return cb(err); }
cb(null, user);
});
});
// Create a new Express application.
// Use application-level middleware for common functionality (Order is important!)
// Initialize Passport and restore authentication state, if any, from the session.
var app = express();
app.use(require('cookie-parser')());
app.use(require('body-parser').urlencoded({ extended: true }));
app.use(require('express-session')({ secret: 'qwerty', resave: false, saveUninitialized: false })); // Step 2.
app.use(passport.initialize());
app.use(passport.session());
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login.html' }),
function(req, res) {
console.log('Logged In: ' + req.user.username);
res.redirect('/');
});
app.get('/logout', function(req, res){
if (req.user != null) {
console.log('Logged Out: ' + req.user.username);
req.logout();
} else {
console.log('Warning: null user logging out');
}
res.redirect('/login.html');
});
app.get('/user', function(req, res){
if (req.user != null) {
res.send(req.user.displayName);
} else {
res.send('ERROR: No current user?');
}
});
function isAuthenticated(req, res, next) {
if (req.user) { // User is logged in
return next();
}
if (req.url.startsWith('/login')) { // Allow login through to avoid infinite loop
return next();
}
res.redirect('/login.html');
}
app.use('/', isAuthenticated, express.static('/public/'));
The db/users.js file:
var records = [
{ id: 1, username: 'jill', password: 'birthday', displayName: 'Jill'}
{ id: 2, username: 'jack', password: 'hello', displayName: 'Jack'}
];
exports.findById = function(id, cb) {
process.nextTick(function() {
var idx = id - 1;
if (records[idx]) {
cb(null, records[idx]);
} else {
cb(new Error('User ' + id + ' does not exist'));
}
});
}
exports.findByUsername = function(username, cb) {
process.nextTick(function() {
for (var i = 0, len = records.length; i < len; i++) {
var record = records[i];
if (record.username === username) {
return cb(null, record);
}
}
return cb(null, null);
});
}
Tumbleweeds!
So it turns out that it was working fine - the problem was just that Chrome reuses its session across tabs. I found a helpful comment buried in this question's answer. One login from Chrome and another from IE works fine, no conflict.
Node + Passport - multiple users

why my koa-passport authenticate parameter user is always undefined?

I'm trying to use koa-passport for koa2, and followed the examples of the author, but i always get "Unauthorized". I used the console.log and found that it even not hit the serializeUser.
var UserLogin = async (ctx, next) =>{
return passport.authenticate('local', function(err, user, info, status) {
if (user === false) {
ctx.body = { success: false }
} else {
ctx.body = { success: true }
return ctx.login(user)
}
})(ctx, next);
};
And then I searched on the web and found another writing of router, it goes to the serializeUser but the done(null, user.id) threw error that "cannot get id from undefined".
let middleware = passport.authenticate('local', async(user, info) => {
if (user === false) {
ctx.status = 401;
} else {
await ctx.login(ctx.user, function(err){
console.log("Error:\n- " + err);
})
ctx.body = { user: user }
}
});
await middleware.call(this, ctx, next)
The auth.js are showed below. Also I followed koa-passport example from the author here and tried to use session, but every request i sent will get a TypeError said "Cannot read property 'message' of undefined". But I think this is not the core problem of authentication, but for reference if that really is.
const passport = require('koa-passport')
const fetchUser = (() => {
const user = { id: 1, username: 'name', password: 'pass', isAdmin: 'false' };
return async function() {
return user
}
})()
const LocalStrategy = require('passport-local').Strategy
passport.use(new LocalStrategy(function(username, password, done) {
fetchUser()
.then(user => {
if (username === user.username && password === user.password) {
done(null, user)
} else {
done(null, false)
}
})
.catch(err => done(err))
}))
passport.serializeUser(function(user, done) {
done(null, user.id)
})
passport.deserializeUser(async function(id, done) {
try {
const user = await fetchUser();
done(null, user)
} catch(err) {
done(err)
}
})
module.exports = passport;
By the way when I use the simple default one, it will just give me a "Not found". But through console.log I can see it actually got into the loginPass.
var loginPass = async (ctx, next) =>{
passport.authenticate('local', {
successRedirect: '/myApp',
failureRedirect: '/'
});
};
In server.js:
// Sessions
const convert = require('koa-convert');
const session = require('koa-generic-session');
app.keys = ['mySecret'];
app.use(convert(session()));
// authentication
passport = require('./auth');
app.use(passport.initialize());
app.use(passport.session());
Thanks a lot for any help!!! :D

Resources