3

I have an Node/Express API serving data to a Vue frontend, and am now adding Passport for authentication and authorization. I have a createUser function which successfully adds the user, but the function hangs when doing so. I'm sure it's just a stupid thing I've missed, like not calling next() (although I did that), and I'd appreciate someone with a clearer head having a look.

//authRoutes.js

const router = require('express').Router();
const { createUser } = require('../controllers/authController');

router.route('/auth/register').post(createUser);

module.exports = router;

//authController.js

'use strict';

const authHelpers = require('../auth/_helpers');
const passport = require('../auth/local');

const handleResponse = (res, code, statusMsg) => {
    res.status(code).json({ status: statusMsg });
};

const createUser = (req, res, next) => {
    // passes correct user and pass
    console.log(req.body);
    return authHelpers
        .createUser(req, res, next)
        .then(() => {
            passport.authenticate('local', (err, user, info) => {
                if (err) {
                    handleResponse(res, 500, 'error');
                    console.log(info);
                }
                if (user) {
                    handleResponse(res, 200, 'success');
                    console.log(info);
                }
            })(req, res, next);
        })
        .catch(next);
};

module.exports = {
    createUser,
};

//auth/_helpers.js

const bcrypt = require('bcryptjs');
const knex = require('../db/connection');

const comparePass = (userPassword, databasePassword) =>
    bcrypt.compareSync(userPassword, databasePassword);

const createUser = req => {
    const salt = bcrypt.genSaltSync();
    const hash = bcrypt.hashSync(req.body.password, salt);
    return knex('users')
        .insert({
            email: req.body.email,
            password: hash,
        })
        .returning('*');
};

module.exports = {
    comparePass,
    createUser,
};

EDIT 1:

As per @cantuket's suggestion, logging what createUser is returning yields the user object, which correctly inserts into the DB:

//console.log('res: ', result)

{ id: 30,
    email: '[email protected]',
    password:
     '$2a$10$WNX.9ur7PlS9ZZvZlJk9Tu9j3lWMjaTlUQ1v7i84dqgHscDupIowW',
    admin: false,
    created_at: 2019-03-01T18:22:53.120Z,
    updated_at: 2019-03-01T18:22:53.120Z,
    last_login: null } 
    ```

EDIT 2:
Thanks to [@cantuket][1] for reminding me to get dirty with console logs, I figured it out by switching 'user' with the returned value (here response), and returning nexts. See below for the fix that worked:

const createUser = (req, res, next) => { return authHelpers .createUser(req, res) .then(response => { passport.authenticate('local', (err, user, info) => { if (err) { console.error(err); console.info(info); handleResponse(res, 500, 'error'); return next(err); } if (!response) { console.error(err); console.info(info); handleResponse(res, 500, 'no user'); return next(err); } if (response) { handleResponse(res, 200, 'success'); next(); } })(req, res, next); }) .catch(err => { console.error(err); console.info(info); handleResponse(res, 500, 'error'); return next(err); }); };



  [1]: https://meta.stackexchange.com/users/461693/cantuket

2 Answers 2

1

Not an Answer:

First thing I'd do is to check what createUser() -> knex().insert() is returning...

 .then(result => {
     console.log('createUser:', result)
        passport.authenticate('local', (err, user, info) => {
            if (err) {
                handleResponse(res, 500, 'error');
                console.log(info);
            }
            if (user) {
                handleResponse(res, 200, 'success');
                console.log(info);
            }
        })(req, res, next);
    })
    .catch(err=> {
       console.log('err createUser:', err)
       next();
    });
Sign up to request clarification or add additional context in comments.

1 Comment

so are neither of these being called console.log(info); ? Also you may want move them above the handleResponse() in case that completes before the console.log()
0

i can see that you are authenticating passport instead of the signed-up user. ensure to use passport in your main entry file, app.js like this.

    const passport = require('passport')

    app.use(passport.initialize())
app.use(passport.session())
passport.use(User.createStrategy()) 
passport.serializeUser((user, done)=>done(null, user.id)); 
passport.deserializeUser((id, done)=>User.findById(id, (err, user)=>done(err,  user)))
                         
app.use((req, res, next)=>{
    res.locals.currentUser = req.user;
    res.locals.title = 'Conforti';
    res.locals.success = req.session.success || '';
    delete req.session.success;
    res.locals.error = req.session.error || ''; 
    delete req.session.error;
    res.locals.csrfToken= req.csrfToken(); 
    req.session.cookie.expires = new Date(Date.now() + 3600000)
    req.session.cookie.maxAge = 3600000
    next();
    });

in your controller you should import the user model and authenticate it like this:

const User = require('../models/users')

this is the postLogin function:

postLogin: async (req, res, next)=>{   
   const {username, password} = req.body;
   const {user, error} = await User.authenticate()(username, password);
   if(!user && error) return next(error);
   req.login(user, (err)=>{
     if(err) return next(err);
     req.session.success = `Welcome back, ${user.username}`;
     const redirectUrl = req.session.redirectTo || '/';
     delete req.session.redirectTo;
     res.redirect(redirectUrl);
    
   });
  },     

this may not be the entire code, but it might help you to spot the error.

you can also check the passport documentation on npmjs.com

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.