1

Im all over the docs, but I cant seem to find a way to update credentials.

This is what I was able to pick up by analyzing the code.

passport.deserializeUser(function(id, done) {
    AppUser.findById(id, function(err, user) {
        done(err, user);
    });
});

DeserializeUser seems useful, but I am not sure how to use it to update a or add fields?

I was trying to hack away and copy the logic from the login and make sense of it.

passport.use('local-update', new LocalStrategy({
    usernameField : 'username',
    passReqToCallback : true
},
function(req, username, done) {

    console.log(req)
    // asynchronous
    // AppUser.findOne wont fire unless data is sent back
    // process.nextTick(function() {

    //     // find a user whose email is the same as the forms email
    //     // we are checking to see if the user trying to login already exists
    //     AppUser.findOne({ 'local.email' :  email }, function(err, user) {
    //         // if there are any errors, return the error
    //         if (err)
    //             return done(err);

    //         // check to see if theres already a user with that email
    //         if (!user) {
    //             //return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
    //             return done(null, false);
    //         } else {

    //             // if there is a user with that email
    //             // create the username
    //             var updateUser = new AppUser();

    //             // set the user's local credentials
    //             newUser.local.email    = email;
    //             newUser.local.password = newUser.generateHash(password);

    //             // save the user
    //             newUser.update(function(err) {
    //                 if (err)
    //                     throw err;
    //                 return done(null, newUser);
    //             });
    //         }

    //     });    

    // });

}));

Then on the form submit I did this.

app.post('/profile', passport.authenticate('local-update', {
    successRedirect : '/', // redirect to the secure profile section
    failureRedirect : '/signup' // redirect back to the signup page if there is an error
    //failureFlash : true // allow flash messages
}));

This results in a failure redirect.

It doesn't work because there is no response, but I need to find the model in mongoDB. I'm trying to see the req in the console first, so that maybe I can see how to find the model, but there is nothing showing up.

Obviously HACKISH code above, but this is the best I could do. I need a concrete answer, I am sure its simple and I am missing it in the docs!

Edit: The idea here is when a user signs up/logs in they provide an email. Once the user is logged in and an account is created they can create a username.

Edit: So I cannot figure out how to make update requests with passport, but in my router I have something like this.

app.post('/', function(req, res) {
    if (req.user) {
        AppUser.findOne({ _id: req.user.id }, function (err, user) {
            user.local.username  = req.body.username;
            user.save(function(err) {
                if (err){
                    console.log('Error')
                } else {
                    console.log('Sucess')
                }
            });
        });
    }
});

The only problem is the browsers default action, it submits the form and keeps the page on an endless reload. But it does update my mongodb model. I had to addon to the Schema, and had to add that property in my passport signup logic.

But I could just add this logic into my client side code, and throw the POST method into backbone and that should work!

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Michael Joseph Aubry
  • 12,282
  • 16
  • 70
  • 135
  • you mean `req.body` doesn't contain the fields you need? – jpgc Mar 26 '14 at 21:57
  • It should give me what I need, but I cannot get that request to respond to the server side CLI console, meaning once it appears in the console then I have access to it as of now I don't. Overall I am quite new and confused, but when I can return to the callback a successRedirect I would be much better off. – Michael Joseph Aubry Mar 26 '14 at 22:03
  • it also requires some mongodb query I tried something like `AppUser.update({'local.email' : 'myemail@gmail.com'}, { $set: { "local.email": "Warner" } });` something static but if the callback returns false the query wont execute deeming anything in `function(req, username, done)` useless. There is obviously something wrong with how I have setup the localStrategy for this specific instance. – Michael Joseph Aubry Mar 26 '14 at 22:05
  • I've changed [my answer](http://stackoverflow.com/a/22673737/2848770), is something like that what you need? – jpgc Mar 26 '14 at 22:30
  • 1
    If the browser gets stuck in an 'endless reloading' it could be because you're not sending any response. To solve that, you could try using `res.send(200)` and `res.send(403)` instead of `console.log('Success')` and `console.log('Error')` . Is that the problem? – jpgc Mar 27 '14 at 00:25
  • Wow I don't know why I didn't think of using the callback to give a response lol. I used a redirect instead `res.redirect('/');` but this works phenomenal. I don't see why this isn't a good solution, there is validation if the user is logged in and all seems well to me. Thanks for taking the time to help, glad we got it. Anyone see anything wrong please object now! :) – Michael Joseph Aubry Mar 27 '14 at 00:41

1 Answers1

1

In cases like this, you can add a callback array as an argument for the Express route.

I guess you can change your verify handler to something like:

function(req, username, done) {
    //perform here only the validations you need to let the login pass
    if (validationSuccess) {
        done();
    } else {
    done('an error occured');
    }
}

So, supposing this function will successfully validate the user credentials, you can write another one:

function doSomethingAfter(req, res, next) {
    //do anything else you need here
    //e.g.
    SomeModel.create(req.body.username);
    //the response is available here
    res.send('Everything ok');
}

Finally, you can edit your routing function

app.post('/profile', [passport.authenticate('local-update', {
    failureRedirect : '/signup' // redirect back to the signup page if there is an error
}), doSomethingAfter]);

That way, you can perform authentication and make anything you want after the request is properly authenticated. If you need to add more functions, you have to add them to the array and call next() on each one.

Hope it helps.

jpgc
  • 764
  • 5
  • 19
  • Thanks for helping, but I am not sure I understand how to incorporate that. I am sure this is probably a good solution. Check out what I came up with in the OP above. – Michael Joseph Aubry Mar 27 '14 at 00:10
  • 1
    My answer is about an express' behavior. When you add an endpoint using, say, `app.post('/foo', handler)`, handler is a function that uses `req`, `res`, and `next` arguments. The `next` argument can be used to iterate in an array of functions asynchronously (each of one taking the same arguments), by calling next() inside of a function to make express call the next one. When you use passport.authenticate, that call returns a function that takes `req`, `res` and `next` arguments, so you can pass it as a member of an array (instead of my `handler` argument), and add another function as a member. – jpgc Mar 27 '14 at 00:44
  • 1+ for the explanation, thanks for this but it makes some sense, but for me personally what I went with is easier for me to understand. I don't see any issues and feels clean. This is a good solution, amazing how you can do one thing multiple ways. – Michael Joseph Aubry Mar 27 '14 at 00:47