0

I am trying to implement Passport into my MERN application, registering users and all other routes work but whenever I hit the /login POST route I get Cannot POST /login (see image below). This only happens when I enter a valid username/password (the error paths work fine). Here is the related code: Passport.js

const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcrypt");

const initialize = async (passport, getUserByEmail, getUserById) => {
  const authenticateUser = async (email, password, done) => {
    const user = await getUserByEmail(email);
    if (user == null) {
      return done(null, false, {msg: "No user with that email"})
    }

    try {
      console.log(`pass: ${password}, hash: ${user.password}`)
      if (await bcrypt.compare(password, user.password)) {
        console.log(user)
        return done(null, user);
      } else {
        return done(null, false, {msg: "Password incorrect"})
      }
    } catch (e) {
      return done(e)
    }
  }
  passport.use(new LocalStrategy({ usernameField: "email"}, authenticateUser))
  passport.serializeUser((user, done) => done(null, user._id));
  passport.deserializeUser(async (id, done) => done(null, await getUserById(id)));
}

module.exports = initialize

This is the main code I'm having issues with, my routes are:

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

const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const ItemModel = require('./Models/Item');
const DepartmentModel = require("./Models/Department");
const PeopleModel = require("./Models/Person");
const HouseModel = require('./Models/House');
const ListModel = require('./Models/List');
const bcrypt = require("bcrypt");
const UsersModel = require('./Models/User');
const passport = require("passport");
const flash = require("express-flash");
const session = require("express-session");
const initialize = require("./Passport")
const mongoStore = require('express-session-mongo');

const getUserByEmail = async (email) => {
  return await UsersModel.findOne({email: email});
}

const getUserById = async (id) => {
  return await UsersModel.findById(id);
}


const app = express()

// middleware
app.use(cors())
app.use(express.json())
app.use(express.urlencoded({ extended: true }));
app.use(flash())
app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
}))
app.use(passport.initialize())
app.use(passport.session())


// connect to mongoDB
mongoose.connect(process.env.DB)

initialize(passport, getUserByEmail, getUserById)

... omitted unrelated code ...

// ---------------------------- //
// -----   AUTH ROUTES    ----- //
// ---------------------------- //

app.delete("/logout", (req, res) => {
  req.logout((err) => {
    if (err) { return next(err); }
    res.json({ msg: "Logged out"});
  });
});

// !!!!!!LOGIN ROUTE!!!!!!!
app.post("/login", passport.authenticate("local"))

app.post("/register", async (req, res) => {
  try {
    const hashedPassword = await bcrypt.hash(req.body.password, 10)
    await UsersModel.create({
      username: req.body.username,
      password: hashedPassword,
      email: req.body.email
    })
    res.json({ msg: "Registered new user"})
  } catch {
    res.json({ msg: "Error"})
  }
})

const checkAuthenticated = (req, res, next) => {
  if (req.isAuthenticated()) {
    return next();
  } 

  res.json({msg: "Not authenticated"});
}

const checkNotAuthenticated = (req, res, next) => {
  if (req.isAuthenticated()) {
    return res.json({msg: "Authenticated"});
  } 

  return next();
}

// ---------------------------- //
// -----   START SERVER   ----- //
// ---------------------------- //

app.listen(process.env.PORT, () => {
  console.log("--- Server is UP and running ---")
})

// ---------------------------- //
// ---------------------------- //

[![enter image description here][1]][1]
[1]: https://i.sstatic.net/GPIRNYPQ.png

7
  • Everything looks ok. Are you sure you've saved all changes to all files and have restarted the Express application? What is process.env.PORT set to? When you start the app, do you see the --- Server is UP and running --- message?
    – Phil
    Commented Jun 20 at 6:08
  • @Phil yes I've restarted the server many times. process.env.PORT is 3001 and I do see the --- Server is UP and running --- message
    – jc22920
    Commented Jun 20 at 6:12
  • Uh, your request data looks a bit mixed up. Shouldn't the email field have userThatWorks and password have passwordThatWorks?
    – Phil
    Commented Jun 20 at 6:12
  • was typing too fast, I used those as placeholders to not reveal my actual email, but yes they should be switched. It validates with my email, but still gives the error.
    – jc22920
    Commented Jun 20 at 6:15
  • 1
    Oh, you're just missing something to handle the request after authentication, ie (req, res) => { res.something(); }. See the Authenticate part at the bottom of this page
    – Phil
    Commented Jun 20 at 6:56

1 Answer 1

1

Here is what I did to fix the issue:

app.post("/login", passport.authenticate("local"), (req, res) => {
    res.status(200)
    res.send('success')
});

It needs an additional handler for it work. If the authentication fails, it will automatically respond with a 401 status code.

You can also directly call passport.authenticate:

app.post("/login", (req, res, next) => {
  passport.authenticate("local", (err, user, info) => {
    // Handle error (e.g., database error)
    if (err) return next(err);
    // Authentication failed (invalid credentials)
    if (!user)
      return res.status(401).json({ message: "Invalid username or password" });
    // Authentication succeeded
    req.logIn(user, (err) => {
      if (err) return next(err);
      // Redirect or send a success response
      return res.json({ message: "Authentication successful", id: user._id });
    });
  })(req, res, next);
});

Here is the code I used to reproduce the problem:

const express = require("express");
const initialize = require("./initialize");
const passport = require("passport");
const session = require("express-session");
const app = express();
app.use(express.json());
app.use(
  session({
    secret: "process.env.SESSION_SECRET",
    resave: false,
    saveUninitialized: false,
  })
);
app.use(passport.initialize());
app.use(passport.session());

const user = {
  _id: "userId",
  password: "passwordThatWorks",
};

const getUserByEmail = async (email) => {
  return user;
};

const getUserById = async (id) => {
  return user;
};

initialize(passport, getUserByEmail, getUserById);

app.post("/login", passport.authenticate("local"), (req, res) => {
    res.status(200)
    res.send('success')
});

app.listen(4000, () => {
  console.log(`Listening on PORT 4000`);
});
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcrypt");

const initialize = async (passport, getUserByEmail, getUserById) => {
  const authenticateUser = async (email, password, done) => {
    const user = await getUserByEmail(email);
    if (user == null) {
      return done(null, false, { msg: "No user with that email" });
    }

    try {
      console.log(`pass: ${password}, hash: ${user.password}`);
    //   if (await bcrypt.compare(password, user.password)) {
      if (true) {
        console.log(user);
        return done(null, user);
      } else {
        return done(null, false, { msg: "Password incorrect" });
      }
    } catch (e) {
      return done(e);
    }
  };
  passport.use(new LocalStrategy({ usernameField: "email" }, authenticateUser));
  passport.serializeUser((user, done) => done(null, user._id));
  passport.deserializeUser(async (id, done) =>
    done(null, await getUserById(id))
  );
};

module.exports = initialize;

Not the answer you're looking for? Browse other questions tagged or ask your own question.