1

Suppose the following User Schema in MongoDB (using Mongoose/Nodejs):

var UserSchema = new Schema({
    email: {
        type: String,
        unique: true,
        required: 'User email is required.'
    },
    password: {
        type: String,
        required: 'User password is required.'
    },
    token: {
        type: String,
        unique: true,
        default: hat
    },
    created_at: {
        type: Date,
        default: Date.now
    },
});

// mongoose-encrypt package
UserSchema.plugin(encrypt, {
    secret: 'my secret',
    encryptedFields: ['email', 'password', 'token', 'created_at']
});

Now assume I want to return the user object from an API endpoint. In fact, suppose I want to return user objects from multiple API endpoints. Possibly as a standalone object, possibly as a related model.

Obviously, I don't want password to be present in the returned structure - and in many cases I wouldn't want token to be returned either. I could do this manually on every endpoint, but I'd prefer a no-thought solution - being able to simply retrieve the user, end of story, and not worry about unsetting certain values after the fact.

I mainly come from the world of Laravel, where things like API Resources (https://laravel.com/docs/5.6/eloquent-resources) exist. I already tried implementing the mongoose-hidden package (https://www.npmjs.com/package/mongoose-hidden) to hide the password and token, but unfortunately it seems as though that breaks the encryption package I'm using.

I'm new to Nodejs and MongoDB in general - is there a good way to implement this?

CGriffin
  • 1,406
  • 15
  • 35
  • You can either project your query or you can bcrypt your password https://www.npmjs.com/package/bcrypt-nodejs – Ashh Jun 10 '18 at 14:50

1 Answers1

2

How to protect the password field in Mongoose/MongoDB so it won't return in a query when I populate collections?

You can use this: Users.find().select("-password"), but this is done whenever you send the queried item to the user (res.json()...) so you can do your manipultions with this field included and then remove it from the user before you send it back (this is using the promise approach, the best practice). And if you want your changes to be used as default you can add "select: false" into the schema object's password field.

Hope this helps :)

Roee
  • 84
  • 5
  • See, I'm trying to avoid needing to do thing manually every time. From a dev perspective I'd rather be required to opt IN to having the password, than opt OUT, and possibly forget to do it on a particular endpoint (or have a future dev unfamiliar with the project forget). 'Scope' might be a good word to describe what I'm looking for. – CGriffin Jun 10 '18 at 20:16
  • In that case you can add "select: false" into the schema object's password field. – Roee Jun 10 '18 at 21:05
  • But then you have to remember to add "Users.find({}).select('+password')" whenever you want to do something with the saved password. – Roee Jun 10 '18 at 21:10
  • Excellent, that's actually exactly what I want. The opt-in security paradigm is much more powerful and secure than opt-out. Better to have to explicitly define the few times I _do_ want the password, than need to explicitly define every other instance where I _don't_. If you can update the answer to reflect the comments I'll accept it. – CGriffin Jun 10 '18 at 23:05