feathersjs-ecosystem / authentication-local

[MOVED] Local authentication plugin for feathers-authentication
https://github.com/feathersjs/feathers
MIT License
26 stars 15 forks source link

User service create method gets called upon each validation #56

Closed marcus-sa closed 6 years ago

marcus-sa commented 6 years ago

Whenever I try to authenticate through REST or socket, the create method on the user service gets called each time. That means the request body gets changed and the bcrypt compare method will actually try to validate the entered password which has been just hashed due to the create method getting called on the user service against the actual database password.

How come this happens?

Config:

{
    secret: Env.get('APP_KEY'),
    cookie: {
      name: 'feathers-jwt',
      enabled: true,
      httpOnly: false,
      maxAge: 60 * 60 * 24 * 1000,
      secure: Env.get('NODE_ENV') === 'production'
    },
    local: {
      entity: 'user',
      service: 'users',
      usernameField: 'username',
      passwordField: 'password'
    }
}

User service:

'use strict'

const auth = require('@feathersjs/authentication')
const local = require('@feathersjs/authentication-local')
const { restrictToOwner } = require('feathers-authentication-hooks')
const { discard } = require('feathers-hooks-common')
const Yup = require('yup')

const validateHook = use('Validation')
const Model = use('Model')

module.exports = class Users extends Model {

  static get createSchema() {
    return Yup.object().shape({
      username: Yup.string().min(4).max(24).required('Username is required!'),
      password: Yup.string().min(6).max(255).required('Password is required!'),
      confirmPassword: Yup.string().required('You must confirm your password')
    })
  }

  static get serviceHooks() {
    return {
      before: {
        find: auth.hooks.authenticate('jwt'),
        get: auth.hooks.authenticate('jwt'),
        create: [validateHook(this.createSchema), discard('confirmPassword'), local.hooks.hashPassword()],
        update: [auth.hooks.authenticate('jwt')],
        patch: [auth.hooks.authenticate('jwt')],
      },
      after: {
        all: local.hooks.protect('password')
      }
    }
  }

  static get tableName() {
    return 'users'
  }

  static attributes({ STRING, INTEGER }) {
    return {
      username: {
        type: STRING,
        allowNull: false
      },
      password: {
        type: STRING,
        allowNull: false
      },
      rank: {
        type: INTEGER,
        defaultValue: 1
      }
    }
  }

}

Authentication service:

'use strict'

const { discard } = require('feathers-hooks-common')
const auth = require('@feathersjs/authentication')
const jwt = require('@feathersjs/authentication-jwt')
const local = require('@feathersjs/authentication-local')

const Users = use('Services/Users')
const Config = use('Config')
const Service = use('Service')

module.exports = class Authentication {

  get createService() { return false }

  get configure() {
    return [
      auth(Config.get('app.auth')),
      jwt(),
      local()
    ]
  }

  async populateUser(hook) {
    const payload = await hook.app.passport.verifyJWT(hook.result.accessToken, Config.get('app.auth'))
    const user = await Users.get(payload.userId)
    hook.result.user = user
  }

  get hooks() {
    return {
      before: {
        create: auth.hooks.authenticate(['jwt', 'local']),
        remove: auth.hooks.authenticate('jwt')
      },
      after: {
        create: [this.populateUser, discard('user.password')]
      }
    }
  }

}
daffl commented 6 years ago

None of the built-in authentication tools call create on the users service. It has to be somewhere in your code but I don't think the snippets show your entire setup. As I mentioned before, the best way to get help with things like this is to share a complete repository that can be cloned and reproduces the issue.

daffl commented 6 years ago

I'm going to close this but please feel free to reopen with a complete breaking example.