0

I've set up a passport local strategy from passport.js so that I can register and authenticate users for my app.

Up till now everything seems to be working fine - network requests go through fine and users are created and succesfully saved to the DB.

However, the redirects within the passport.authenticate don't seem to be working.

authRoutes.js:

const passport = require('passport');

module.exports = app => {
  app.post(
    '/register',
    passport.authenticate('local-signup', {
      successRedirect: '/',
      failureRedirect: '/'
    })
  );
};

passport.js:

const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const mongoose = require('mongoose');
const User = mongoose.model('users');

passport.serializeUser((user, done) => {
  console.log('serialize:', user.id);
  done(null, user.id);
});

passport.deserializeUser((id, done) => {
  User.findById(id).then(user => {
    console.log('deserialize:', user);
    done(null, user);
  });
});

// Local signup strategy
passport.use('local-signup', new LocalStrategy(
  {
    usernameField: 'email',
    passwordField: 'password',
    passReqToCallback: true
  },
  (req, email, password, done) => {
    console.log('req:', req.body);

    User.findOne({ 'local.email': email }, (err, user) => {
      console.log('error:', err);
      console.log('user:', user);
      if (err) { return done(err); }

      if (user) {
        return done(null, false, { message: 'That email already exists' })
      } else {
        new User({
          'local.email': email,
          'local.password': password
        }).save(err => {
          if (err) { throw err };
        }).then(user => {
          console.log('new user:', user);
          return done(null, user)
        });
      }
    });

  }
));

Github repo: https://github.com/drhectapus/Voting-App

UPDATE:

I cleaned up this bit of code because it uses a mix of callbacks and promises:

new User({
  'local.email': email,
  'local.password': password
}).save(err => {
  if (err) { throw err };
}).then(user => {
  console.log('new user:', user);
  return done(null, user)
});

When I clean up the above code to this:

new User({
  'local.email': email,
  'local.password': password
}).save((err, user) => done(err, user));

It successfully saves the user to the DB with no errors, but still doesn't redirect properly.

However, when I cleaned up the above code to this:

new User({
  'local.email': email,
  'local.password': password
})
.then(user => done(null, user))
.catch(err => done(err));

I get the following console errors:

In browser console:

POST http://localhost:3000/register 500 (Internal Server Error)
Uncaught (in promise) Error: Request failed with status code 500
    at createError (createError.js:16)
    at settle (settle.js:18)
    at XMLHttpRequest.handleLoad (xhr.js:77)

In terminal console:

TypeError: (intermediate value).then is not a function
[0]     at User.findOne (/Users/Joseph/workspace/voting-app/services/passport.js:40:10)
[0]     at model.Query.<anonymous> (/Users/Joseph/workspace/voting-app/node_modules/mongoose/lib/model.js:3919:16)
[0]     at /Users/Joseph/workspace/voting-app/node_modules/kareem/index.js:273:21
[0]     at /Users/Joseph/workspace/voting-app/node_modules/kareem/index.js:131:16
[0]     at _combinedTickCallback (internal/process/next_tick.js:131:7)
[0]     at process._tickCallback (internal/process/next_tick.js:180:9)
[0] [nodemon] app crashed - waiting for file changes before starting...
[1] Proxy error: Could not proxy request /register from localhost:3000 to http://localhost:5000.
[1] See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (ECONNRESET).
[1] 
[1] [HPM] Error occurred while trying to proxy request /register from localhost:3000 to http://localhost:5000 (ECONNRESET) (https://nodejs.org/api/errors.html#errors_common_system_errors)
doctopus
  • 5,349
  • 8
  • 53
  • 105

1 Answers1

0

It's probably caused by this:

new User({
  'local.email': email,
  'local.password': password
}).save(err => {
  if (err) { throw err };
}).then(user => {
  console.log('new user:', user);
  return done(null, user)
});

Which uses a strange mix of callbacks and promises.

Either use this (using a callback):

new User({
  'local.email': email,
  'local.password': password
}).save((err, user) => done(err, user));

Or this (using promises):

new User({
  'local.email': email,
  'local.password': password
}).save()
  .then(user => done(null, user))
  .catch(err => done(err));

EDIT: your edit added this relevant piece of information: XMLHttpRequest.handleLoad, so you're using XMLHttpRequest ("AJAX") to call /register.

In that case, redirects are handled as part of the AJAX request flow (the response to the AJAX request will be the redirect), and it won't redirect the page on which the AJAX request occurs.

To implement changing the page, you need to handle that client-side. There are various questions with answers on SO that provide an idea on how that could be implemented:

robertklep
  • 198,204
  • 35
  • 394
  • 381
  • I did as you said and updated my original post with the outcomes I got. Seems like the first one still doesn't redirect properly, and the second one i get a bunch of console errors – doctopus Oct 14 '17 at 14:29
  • @JosephLiu the errors were caused because I forgot to add `.save()`, see edit. I'll add some additional explanation on why the redirect _seems_ to not work properly. – robertklep Oct 14 '17 at 14:32
  • That makes sense then. I'm using react/redux on the front-end. Does that mean i should use react-router-dom to add a `history.push('/')` when I call the action creator? – doctopus Oct 14 '17 at 15:16
  • If you're using a client-side router already, it's probably best to instruct it to perform the "redirect". If you're not using such a router, it may be easier to just use `window.location = '/'` (or [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History_API#The_pushState()_method)). – robertklep Oct 14 '17 at 18:35