Help with implementing Passport with Postgresql database

Hello Everone!

I am having issues with setting up Passport:
I have a Db connected with my server, I am able to register users.
I wanted to implement a Passport local Strategy to look for a user in the db, login and save that into a session.
The code bellow does not return any errors but the app doesn’t load at all…
Any suggestion on what is happening? or any suggestions at all ?

(I will add cart routes, use a router later on, but i wanted to set up the authentication process first as it seams to be the hardest)

This is my passport-config file:

const LocalStrategy = require ('passport-local');
const bcrypt = require('bcrypt');



function passportConfig(passport, getUserByEmail, getUserById){
const authenticateUser = async (email, password, done) => {
    const user = await getUserByEmail(email)
    if (user.length == 0){
        return done(null, false, {message: 'No user found'})
    } try{
        if (await bcrypt.compare(password, user[0].password)){
        return done (null, user[0])
        }else{
            return done (null, false, {message: 'Incorrect Password'})
        }
    }catch (err){
        return done (err)
    }}

    passport.use('local', new LocalStrategy({usernameField: 'email', passReqToCallback : true},
        authenticateUser))
         
    passport.serializeUser((user, done)=> {done(null, user)});
    passport.deserializeUser(async (id, done)=> {
        const user = await getUserByID(id);
        done(null, user[0]);
    });
}

module.exports = passportConfig;

and my server file :

if(process.env.NODE_ENV !== 'production'){
require('dotenv').config()
};

const express = require("express");
const app = express();
const expressLayouts = require("express-ejs-layouts");
const bcrypt = require('bcrypt');
const flash = require("express-flash");
const session = require('express-session');

//body parser to handle conversion to/from json:
const bodyParser = require("body-parser");
app.use(bodyParser.json());

//Connection to DataBase:
const client = require("./database");
client.connect();

//Setting up the app:

app.set('view engine', 'ejs')
app.set('views', __dirname +'/views')
app.set('layout', 'layouts/layout')
app.use(express.urlencoded({ extended: false}))
app.use(expressLayouts)
app.use(express.static('public'))
app.use(flash)

app.use(session({
    secret: 'secret',
    resave: false,
    saveUninitialized: false,
    cookie: {
        secure: false,
        maxAge: 24 * 60 * 60 * 1000
      }
}))

//Passport implement:
const passport = require('passport');
const passportConfig = require('./passport-config');

passportConfig(passport, 
    async email =>{
        try{
            const userQuery = `SELECT * FROM users WHERE email = ${email}`;
            const results = await client.query(userQuery)
            return results.rows;
        }catch (err){
            return (err)
        }
    },
    async id =>{
        try{
            const idQuery = `SELECT * FROM users WHERE id = ${id}`;
            const results = await client.query(idQuery)
            return results.rows
        }catch (err){
            return (err)
        }
    }
)

app.use(passport.initialize())
app.use(passport.session())

//ROUTES  /// potentially use router later:
app.get ('/', (req,res)=>{
    res.render('index.ejs')
});

app.get ('/login', (req,res)=>{
    res.render('login.ejs')
});
app.post ('/login', passport.authenticate('local',{
    successRedirect: '/',
    failureRedirect: '/login',
    failureFlash: true
}));


app.get ('/register', (req,res)=>{
    res.render('register.ejs')
});

app.post ('/register', async (req,res)=>{
    //check if user is not already registered
    const emailExists = async (email) => {
        const emailQuery = (`SELECT * FROM users WHERE email = '${email}' `)
        const data = await client.query(emailQuery, (err)=>{
            if (!data) {return false}
            if (err) {console.log(err)}
            else return true
    })
    }
   try {
    if (emailExists){
        res.redirect('/login')
    }else {
        const hashedPassword = await bcrypt.hash(req.body.password, 10);
        const user = req.body;
        let insertquery = `INSERT INTO users(name, email, password) 
                       VALUES('${user.name}', '${user.email}', '${hashedPassword}')`

        client.query(insertquery, (err) =>{
            if(!err){
                res.redirect('/login')  
            } else{ 
                console.log(err.message)
            }})
        client.end;
    }
   }catch {
        res.redirect('/register')
    }
});

app.listen(process.env.PORT || 3000);

Not sure if you’ve solved your issue or not yet.
A couple points of notice…

  • You should probably move your serializeUser, deserializeUser, and passport.use out of that passportConfig function.

  • You can require passport directly at the top of your passport-config file instead of passing it in as well.

  • At this point there would be no need to have an authenticateUser function inside of the passport config function.

  • Since you aren’t accessing the req object inside of the authenticateUser function, you don’t need to passReqToCallback.

  • Also you should be requiring (‘passport-local’).Strategy instead of ('passport-local)

  • passport.deserializeUser isn’t supposed to get the user from the database, it is supposed to retrieve it from the session which was put there when you authenticate, and attach it to the req.body. Therefore you should just return done(null, user).

  • I would also move the getUserByEmail arrow function into the passport-config file and make it callable. Also since you don’t have to call getUserById inside deserialize user, you don’t event need that function anymore.

  • You can then just require the whole passport-config file at the top of your server file.

  • After these changes the code might look something like below.

passport-config:

const localStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt');
const passport = require('passport');
const client = require("./database");

const getUserByEmail = async email =>{
        try{
            const userQuery = `SELECT * FROM users WHERE email = ${email}`;
            const results = await client.query(userQuery)
            return results.rows;
        }catch (err){
            return (err)
        }
    },

const passportConfig = new LocalStrategy({usernameField: 'email'},
    async function (email, password, done) {
        const user = await getUserByEmail(email);
        if(user.length == 0) {
            return done(null, false, {message: 'No user found'})
        }

        const matchedPassword = await bcrypt.compare(password, user[0].password);
        if(!matchedPassword) return done(null, false, {message: 'Incorrect Password'});

        return done(null, user);
    }
);

passport.use('local', passportConfig);

passport.serializeUser((user, done) => {
    done(null, user);
});

passport.deserializeUser((user, done) => {
    return done(null, user);
});

server file:

if(process.env.NODE_ENV !== 'production'){
require('dotenv').config()
};

const express = require("express");
const app = express();
const expressLayouts = require("express-ejs-layouts");
const bcrypt = require('bcrypt');
const flash = require("express-flash");
const session = require('express-session');
require('./passport-config');

//body parser to handle conversion to/from json:
const bodyParser = require("body-parser");
app.use(bodyParser.json());

//Connection to DataBase:
const client = require("./database");
client.connect();

//Setting up the app:

app.set('view engine', 'ejs')
app.set('views', __dirname +'/views')
app.set('layout', 'layouts/layout')
app.use(express.urlencoded({ extended: false}))
app.use(expressLayouts)
app.use(express.static('public'))
app.use(flash)

app.use(session({
    secret: 'secret',
    resave: false,
    saveUninitialized: false,
    cookie: {
        secure: false,
        maxAge: 24 * 60 * 60 * 1000
      }
}))

//Passport implement:
const passport = require('passport');

app.use(passport.initialize())
app.use(passport.session())

//ROUTES  /// potentially use router later:
app.get ('/', (req,res)=>{
    res.render('index.ejs')
});

app.get ('/login', (req,res)=>{
    res.render('login.ejs')
});
app.post ('/login', passport.authenticate('local',{
    successRedirect: '/',
    failureRedirect: '/login',
    failureFlash: true
}));


app.get ('/register', (req,res)=>{
    res.render('register.ejs')
});

app.post ('/register', async (req,res)=>{
    //check if user is not already registered
    const emailExists = async (email) => {
        const emailQuery = (`SELECT * FROM users WHERE email = '${email}' `)
        const data = await client.query(emailQuery, (err)=>{
            if (!data) {return false}
            if (err) {console.log(err)}
            else return true
    })
    }
   try {
    if (emailExists){
        res.redirect('/login')
    }else {
        const hashedPassword = await bcrypt.hash(req.body.password, 10);
        const user = req.body;
        let insertquery = `INSERT INTO users(name, email, password) 
                       VALUES('${user.name}', '${user.email}', '${hashedPassword}')`

        client.query(insertquery, (err) =>{
            if(!err){
                res.redirect('/login')  
            } else{ 
                console.log(err.message)
            }})
        client.end;
    }
   }catch {
        res.redirect('/register')
    }
});

app.listen(process.env.PORT || 3000);