10

There are some irreversible actions that user can do in my app. To add a level of security, I'd like to verify that the person performing such an action is actually the logged in user. How can I achieve it?

  • For users with passwords, I'd like a prompt that would ask for entering user password again. How can I later verify this password, without sending it over the wire?

  • Is a similar action possible for users logged via external service? If yes, how to achieve it?

Hubert OG
  • 19,314
  • 7
  • 45
  • 73
  • You need a security system. Start here: http://stackoverflow.com/q/10099843 – Robert Harvey Aug 13 '13 at 16:34
  • That's completely unrelated. I've got a working app with `accounts-password` installed. I don't want to create a whole security system, I just want to verify the already logged in user. – Hubert OG Aug 13 '13 at 17:43

3 Answers3

21

I can help with the first question. As of this writing, meteor doesn't have a checkPassword method, but here's how you can do it:

On the client, I'm going to assume you have a form with an input called password and a button called check-password. The event code could look something like this:

Template.userAccount.events({
  'click #check-password': function() {
    var digest = Package.sha.SHA256($('#password').val());
    Meteor.call('checkPassword', digest, function(err, result) {
      if (result) {
        console.log('the passwords match!');
      }
    });
  }
});

Then on the server, we can implement the checkPassword method like so:

Meteor.methods({
  checkPassword: function(digest) {
    check(digest, String);

    if (this.userId) {
      var user = Meteor.user();
      var password = {digest: digest, algorithm: 'sha-256'};
      var result = Accounts._checkPassword(user, password);
      return result.error == null;
    } else {
      return false;
    }
  }
});

For more details, please see my blog post. I will do my best to keep it up to date.

David Weldon
  • 63,632
  • 11
  • 148
  • 146
  • I want to use this, but as it relies on undocumented internals, it makes me a little uneasy. Are you using this in a production app? – Mike Turley Aug 27 '13 at 14:26
  • 1
    I am using it a production app, and you are right to feel uneasy about this - I certainly do. – David Weldon Aug 27 '13 at 14:47
  • I'm trying it out now, and I get a "TypeError: Cannot read property 'Client' of undefined". It looks like Meteor._srp is undefined in the latest Meteor :( – Mike Turley Aug 27 '13 at 15:42
  • Thank you for keeping this answer updated, @David. I hope eventually we can reach a way to do this that is version-independent. – Mike Turley Mar 10 '14 at 22:31
  • @DavidWeldon it's not working (version 1.4). always got Incorrect password despite correct current password – Abdul Hameed Oct 18 '16 at 14:47
  • @AbdulHameed I'd recommend double checking your implementation - this still works for me in meteor 1.4.2. – David Weldon Oct 27 '16 at 21:26
0

I haven't done this before, but I think you will need something like this on your server


    Accounts.registerLoginHandler(function(loginRequest) {
        console.log(loginRequest)
        var userId    = null;
        var username  = loginRequest.username;
        // I'M NOT SURE HOW METEOR PASSWORD IS HASHED...
        // SO YOU NEED TO DO A BIT MORE RESEARCH ON THAT SIDE
        // BUT LET'S SAY YOU HAVE IT NOW
        var password  = loginRequest.password;

        var user = Meteor.users.findOne({
            $and: [
                {username: username},
                {password: password} 
            ]
        });
        if(!user) {
            // ERROR
        } else {
            // VERIFIED
        }
    });

then you can call this function from the client side like this:


    // FETCH THE USERNAME AND PASSWORD SOMEHOW
    var loginRequest = {username: username, password: password};

    Accounts.callLoginMethod({
        methodArguments: [loginRequest]
    });

I have a project on github for different purpose, but you can get a sense of how it is structured: https://github.com/534N/apitest

Hope this helps,

Sean Yang
  • 268
  • 1
  • 12
0

I have found the best way to validate the users password is to use the Accounts.changePassword command and pass in the same password for old and new password. https://docs.meteor.com/api/passwords.html#Accounts-changePassword

Accounts.changePassword(this.password, this.password, (error) => {
  if(error) {
    //The password provided was incorrect
  }
})

If the password provided is wrong, you will get an error back and the users password will not be changed.

If the password is correct, the users password will be updated with the same password as is currently set.

PrestonDocks
  • 4,851
  • 9
  • 47
  • 82