Passport authentication works when login, but fails when register

Viewed 119

I am learning passport.js and session, and am trying to add a local login feature to my website.

What I was trying to do is as follows:

  • Secret page: When users are authenticated, they can access to the secret page, otherwise they will be transfered to the login page.
  • Login page: If the username and password match, users are authenticated and are transfered to the secret page, otherwise they would be transfered back to the login page.
  • Register page: Users provide username and password, a new MongoDB document is created and stored in my database, meanwhile, the user is authenticated in this session and are transfered to the secret page.

My Problem:

  • Login page works fine: The authentication process in the login page works perfectly fine. When logined, a cookie is sent to the browser, the user is authenticated in this session and is successfully accessed to the secret page.
  • Register page data insert works fine: After register, the new password and username is successfully saved in the MongoDB database. User could login with this newly registered username.
  • Register page authentication failed: The register page, although using the same passport.authenticate() function, failed in the authentication process. I didn't get any error messages on my console, either.

I searched on Google and tried several methods of passport authentication, and they all worked very well on the 'login' POST Request, but failed on the 'register' POST Request. I have read the documentation of passport-local and passport-local-mongoose. I have also tried this solution. But they all failed in the authentication process in the register page. I use express-session, passport, passport-local-mongoose packages.

I'm wondering if my understanding of passport authentication is still lacking? Thank you so much for your help and patience!

My Code:

EJS File - Register Page:

<!-- ... -->
<form action="/register" method="POST">
  <div class="form-group">
    <label for="email">Email</label>
    <input type="email" class="form-control" name="username">
  </div>
  <div class="form-group">
    <label for="password">Password</label>
    <input type="password" class="form-control" name="password">
  </div>
  <button type="submit" class="btn btn-dark">Register</button>
</form>
<!-- ... -->

JS File:

require('dotenv').config();

const express = require('express');
const app = express();
const port = 3000;

const ejs = require('ejs');

const session = require('express-session');
const passport = require('passport');
const passportLocalMongoose = require('passport-local-mongoose')

app.use(express.urlencoded({
  extended: true
}));
app.use(express.static("public"));
app.set("view engine", "ejs");

//session and passport set up
app.use(session({
  secret: process.env.SECRET,
  resave: false,
  saveUninitialized: true,
  cookie: {
    sameSite: 'lax'
  },
}))

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

//user database set up ////////
const mongoose = require("mongoose");

main().catch(err => console.log(err));
async function main() {
  await mongoose.connect('mongodb://localhost:27017/userDB');
}

const userSchema = new mongoose.Schema({
  username: {
    type: String,
    unique: true
  },
  password: String
})

userSchema.plugin(passportLocalMongoose)

const User = mongoose.model("User", userSchema)

passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
//user database set up end ///////

//GET Request
app.get("/", function(req, res) {
  res.render("home");
})

app.get("/login", function(req, res) {
  res.render("login");
})

app.get("/register", function(req, res) {
  res.render("register");
})

//Secret Page ////////////////////////////////
app.get("/secrets", function(req, res) {
  if (req.isAuthenticated()) {
    res.render("secrets")
  } else(
    res.redirect("/login")
  )
})

app.get('/logout', function(req, res) {
  req.logout(function(err) {
    if (err) {
      console.log(err);
    }
    res.redirect('/');
  });
});

//POST request
//Register POST Request ////////////////////////////////
app.post("/register", function(req, res) {
  User.register(new User({
      username: req.body.username
    }), req.body.password,
    function(err, user) {
      if (err) {
        console.log(err);
        res.redirect('/register')
      }
      passport.authenticate('local'), function(req, res) {
        res.redirect("/secrets");
      }
    }
  )
})

app.post('/login', passport.authenticate('local', {
  failureRedirect: '/login',
}), function(req, res) {
  res.redirect("/secrets");
});

app.listen(port, function() {
  console.log("start listening to port 3000")
})

1 Answers

I tried this answer by adding a parameter 'returnCode' to the call back of the passport authenticate function. Although the return code logged is 'undefined', the code successfully worked! I still don't know precisely why it worked simply by adding a parameter, but I think that's due to my lack of understanding of passport?

One thing I found very unhelpful is that the example page on the passport-local documentation is 404 not found. I wonder if there are any helpful examples I could find to study passport-local?

Here's my Code

app.post("/register", function(req, res) {
  User.register(new User({
      username: req.body.username
    }), req.body.password,
    function(err, user) {
      if (err) {
        console.log(err);
        res.redirect('/register')
      } else {
        passport.authenticate('local', {})(req, res, function(returnCode) {
          console.log(returnCode); //return: undefined
          res.redirect('/secrets');
        })
      }
    }
  )
})
Related