Search code examples
expresspassport.js

How to save user data in signup/register using passport.js with express server


I am working to implement passport.js in my react/node/express/sequelize app.

I currently have middleware working for logging a user in, and checking if the user is authenticated. However, when a new user signs up or registers, their user data is not being saved to the server session (even though it is created in the DB). This means after a user registers, they have to go to the login page, enter their credentials and hit login before their session is saved.

My login function is simple:

    router.post('/login', passport.authenticate('local'), (req, res) => {
        //console.log(req);
        console.log("Is authenticated: " + req.isAuthenticated());
        res.json(req.user);
      });

it uses passport.authenticate local strategy, which I've defined as:

passport.use(new LocalStrategy(
  {
    usernameField: 'email',
  },

  ((email, password, done) => {
    User.findOne({
      where: {
        email,
      },
    }).then((dbUser) => {
      if (!dbUser) {
        return done(null, false, {
          message: 'Incorrect email.',
        });
      }
      if (!dbUser.validPassword(password)) {
        return done(null, false, {
          message: 'Incorrect password.',
        });
      }
      return done(null, dbUser);
    });
  }),
));

I know from the passport documentation and from looking at other questions that the passport.authenticate local strategy automatically calls the req.login() function, which serializes my user information and saves it in the server session.

My main issue is I'm not sure exactly how to implement this during my register function.

    router.post('/signup', (req, res) => {
        const user = {
            first_name: req.body.first_name,
            last_name: req.body.last_name,
            email: req.body.email,
            password: req.body.password,
        };

        User.findOrCreate({where: {email: user.email}, defaults: user})
        .then(data => {
            res.send(data);
        })
        .catch(err => {
            res.status(500).send({
            message:
                err.message || "Some error occurred while creating the User."
            });
        });
    });

I've tried calling req.login() after findOrCreate, but I get an error:

(node:42313) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

If I use my local strategy, I get an unauthorized response (since the credentials I'm using to authorize are not yet in the DB).

I figure I need to make a custom strategy for sign in, but it's not clear to me if that's the right approach, or how I would specify it.


Solution

  • I fixed this by adding req.login before res.send:

    router.post('/signup', (req, res) => {
            const user = {
                first_name: req.body.first_name,
                last_name: req.body.last_name,
                email: req.body.email,
                password: req.body.password,
            };
    
            User.findOrCreate({where: {email: user.email}, defaults: user})
            .then(data => {
             
    
                req.login(data[0], function(err) {
                    if (err) {
                        console.log("login function erroring out with: " + err)
                    }
                });
    
                res.send(data);
    
                
            })
            .catch(err => {
                res.status(500).send({
                message:
                    err.message || "Some error occurred while creating the User."
                });
            });
        });