Need Help on "How to Use Passport Strategies" on Advanced Node and Express

What’s happening:
I tried adding the middlewares I needed, along with a route for /login, but when I tried to run the code, I got Cannot GET / message in the browser window. When I completed the previous challenge, that message had gone away and I could see the login form. So what did I do wrong this time? I need some help here.

My code so far

"use strict";
require("dotenv").config();
const express = require("express");
const myDB = require("./connection");
const fccTesting = require("./freeCodeCamp/fcctesting.js");
const session = require("express-session");
const passport = require("passport");
const ObjectID = require("mongodb").ObjectID;
const LocalStrategy = require("passport-local");
const bodyParser = require("body-parser");

const app = express();

app.set("view engine", "pug");

fccTesting(app); //For FCC testing purposes
app.use("/public", express.static(`${process.cwd()}/public`));

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: true,
  saveUninitialized: true,
  cookie: { secure: false }
}));

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

myDB(async client => {
  const myDataBase = await client.db("database").collection("users");

  app.route("/").get((req, res) => {
    res.render("pug", {
      title: "Connected to Database",
      message: "Please login",
      showLogin: true
    });
  });

  app.use(bodyParser.urlencoded({ extended: true }));
  app.use(passport.authenticate("local", { failedRedirect: "/" }));
  app.route("/login").post((req, res) => {
    if (req.body) {
      console.log(req.body);
    }
  });

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

  passport.deserializeUser((id, done) => {
    myDataBase.findOne({ _id: new ObjectID(id) }, (err, doc) => {
      done(null, doc);
    });
  });

  passport.use(new LocalStrategy(
    (username, password, done) => {
      myDataBase.findOne({ username: username }, (err, user) => {
        console.log(`User ${username} has attempted to log in`);
        if (err) {
          return done(err);
        }
        if (!user) {
          return done(null, false);
        }
        if (password !== user.password) {
          return done(null, false);
        }
        return done(null, user);
      });
    }
  ));
}).catch(e => {
  app.route("/").get((req, res) => {
    res.render("pug", {
      title: e,
      message: "Unable to login"
    });
  });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Listening on port ${PORT}`);
});

My browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 Edg/90.0.818.56.

Challenge: How to Use Passport Strategies

Link to the challenge:

I thought I’d first try to see what the POST request body looks like, but I can’t do that until I somehow resolve this issue. So yeah, please help with that first. Thanks.

Hello there,

Unfortunately, while this may work for the app in this lesson, the tests specifically need the middleware to be mounted inline with the route.

This is done by just passing another argument with the middleware before your function(req,res) with your response!

This is best practice, anyway, because it prevents the middleware from accidentally being used on a lower-declared route.

I might also encourage you to mount the bodyParser middleware outside of the database function, just for parity between the current expected solution.

I haven’t tried to see yet if it passes the test or not. I just want to fix the “Cannot GET /” error message in the browser window first. Could you help me troubleshoot that?

And how do I use a middleware inline with the route that it’s for?

The passportjs docs has an example of it.

Sorry, I missed that.

I cannot see anything else amiss. So, would you mind sharing a link to all of your code?

I haven’t touched anything in the distro except server.js which I copy-pasted all of the code from. But just in case: boilerplate-advancednode - Replit.

I forked your code, and it runs as expected…did you definitely add the SESSION environment variable?

SESSION_SECRET? If so, then yes. It could be a bad one if it’s the cause.

I did this:

"use strict";
require("dotenv").config();
const express = require("express");
const myDB = require("./connection");
const fccTesting = require("./freeCodeCamp/fcctesting.js");
const session = require("express-session");
const passport = require("passport");
const ObjectID = require("mongodb").ObjectID;
const LocalStrategy = require("passport-local");
const bodyParser = require("body-parser");

const app = express();

app.set("view engine", "pug");

fccTesting(app); //For FCC testing purposes
app.use("/public", express.static(`${process.cwd()}/public`));

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

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(bodyParser.urlencoded({ extended: true }));
myDB(async client => {
  const myDataBase = await client.db("database").collection("users");

  app.route("/").get((req, res) => {
    res.render("pug", {
      title: "Connected to Database",
      message: "Please login",
      showLogin: true
    });
  });

  app.route("/login").post(passport.authenticate("local", 
  { failedRedirect: "/" }), 
  (req, res) => {
    if (req.body) {
      console.log(req.body);
    }
  });

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

  passport.deserializeUser((id, done) => {
    myDataBase.findOne({ _id: new ObjectID(id) }, (err, doc) => {
      done(null, doc);
    });
  });

  passport.use(new LocalStrategy(
    (username, password, done) => {
      myDataBase.findOne({ username: username }, (err, user) => {
        console.log(`User ${username} has attempted to log in`);
        if (err) {
          return done(err);
        }
        if (!user) {
          return done(null, false);
        }
        if (password !== user.password) {
          return done(null, false);
        }
        return done(null, user);
      });
    }
  ));
}).catch(e => {
  app.route("/").get((req, res) => {
    res.render("pug", {
      title: e,
      message: "Unable to login"
    });
  });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Listening on port ${PORT}`);
});

and now the error message is gone again. I can see the page properly now.

Edit: Error came back.

I tried to login but I got “Unauthorized” in the browser window. Then I tried stopping and running the server again and the “Cannot GET /” error came back (in the browser window).

I had the wrong thing for the second argument to passport.authenticate; I’d had failedRedirect when it should be failureRedirect. I fixed that, but I still have that problem with the “Cannot GET /” message appearing in the browser window.

But the tests pass. I completed the challenge. I wonder if my SESSION_SECRET value is a bad one.

I am not sure what a bad one would be… I just used ‘12345’, but any string should do.


Can you test your code in a different environment? Perhaps locally, or on CodeSandbox/Glitch? It could have something to do with Replit/your Replit account.

Yeah, that seems to have helped. Thanks.

I’m curious. Did you use a .env file or the interface they provide? If it was a .env file I just wonder if it would have worked using the interface instead. Just so we know if there is an issue with using the (deprecated) .env file setup.

I’m using a Secrets file. I fixed the issue already.

It’s impossible to use a .env file on Repl anyway.

So what do you get back from process.env when you log it out?

console.log(process.env['SESSION_SECRET'])

I’m only asking to see if there is a problem we should be aware of.

I thought they still had some automatic migration in place.

You have to use Secrets on Repl now. They’ve taken away users’ ability to use a .env file.

I opened a new thread for the next challenge for now. passport became undefined when I added the code for the challenge. I added the code inside the DB function’s callback (in the client function passed to DB). Full current code is in the other thread.

I’ll try to do what you asked after I’ve fixed that issue. I just have to try adding the line console.log(process.env["SESSION_SECRET"], right? I’ll have to use a template string, I think, but that’s not a problem.

Yes, I’m just wondering if you are able to get the variable or not.

Also, what environment did you switch to that fixed the issue?

I changed the value for the SESSION_SECRET variable. I had a bunch of random letters before, but I changed it a meaningful string of characters. I don’t know why it worked, though.

Where do I put the code? Inside the DB function or outside it?

Oh, I thought you had to switch away from replit to get it to work. That is why I asked.

I don’t see any information about limitations on the secret string (like accepted characters, or whatnot). But the “meaningfulness” of the string surely doesn’t matter.

Yeah, I’m sure that doesn’t matter. Which is why I’m confused.