Home

Awesome

feathers-authentication-hooks

Important: The setField hook from this repository has moved to feathers-hooks-common. Also see the documentation

Greenkeeper badge Build Status Dependency Status Download Status

A hook that helps limiting and associating user requests

$ npm install feathers-authentication-hooks --save

feathers-authentication-hooks contains a Feathers hook that allows to set query or data properties based on other existing properties (like an authenticated user or organization id).

Note: feathers-authentication-hooks v1.0.0 and later requires Feathers 4 or later.

setField

The setField hook allows to set a field on the hook context based on the value of another field on the hook context.

Options

Important: This hook should be used after the authenticate hook when accessing user fields (from params.user).

Examples

Limit all external access of the users service to the authenticated user:

Note: For MongoDB, Mongoose and NeDB params.user.id needs to be changed to params.user._id. For any other custom id accordingly.

const { authenticate } = require('@feathersjs/authentication');
const { setField } = require('feathers-authentication-hooks');

app.service('users').hooks({
  before: {
    all: [
      authenticate('jwt'),
      setField({
        from: 'params.user.id',
        as: 'params.query.id'
      })
    ]
  }
})

Only allow access to invoices for the users organization:

const { authenticate } = require('@feathersjs/authentication');
const { setField } = require('feathers-authentication-hooks');

app.service('invoices').hooks({
  before: {
    all: [
      authenticate('jwt'),
      setField({
        from: 'params.user.organizationId',
        as: 'params.query.organizationId'
      })
    ]
  }
})

Set the current user id as userId when creating a message and only allow users to edit and remove their own messages:

const { authenticate } = require('@feathersjs/authentication');
const { setField } = require('feathers-authentication-hooks');

const setUserId = setField({
  from: 'params.user.id',
  as: 'data.userId'
});
const limitToUser = setField({
  from: 'params.user.id',
  as: 'params.query.userId'
});

app.service('messages').hooks({
  before: {
    all: [
      authenticate('jwt')
    ],
    create: [
      setUserId
    ],
    patch: [
      limitToUser
    ],
    update: [
      limitToUser
    ]
    remove: [
      limitToUser
    ]
  }
})

Migrating to v1.0.0

The previous versions of feathers-authentication-hooks contained several hooks that required more detailed configuration and knowledge about the application and authentication. Due to improvements in the database adapters in Feathers 4 those hooks can now all be replaced with the setField hook and a more explicit configuration.

queryWithCurrentUser

Before:

const hooks = require('feathers-authentication-hooks');

app.service('messages').before({
  find: [
    hooks.queryWithCurrentUser({ idField: 'id', as: 'sentBy' })
  ]
});

Now:

const { setField } = require('feathers-authentication-hooks');

app.service('messages').before({
  find: [
    setField({
      from: 'params.user.id',
      as: 'params.query.sentBy'
    })
  ]
});

Dot separated paths in queries (previously with the expandPaths option) are possible by passing an array as the field name (using Lodash _.set internally):

const { setField } = require('feathers-authentication-hooks');

app.service('messages').before({
  find: [
    setField({
      from: 'params.user.id',
      as: [ 'params', 'query', 'nested.document.sentBy' ]
    })
  ]
});

restrictToOwner

Due to improvements in the Feathers 4 database adapters restricting to an owner works the exact same as a queryWithCurrentUser. It will now throw a NotFound instead of a Forbidden error which is also more secure since an unauthorized user does not get the information if the record exists and no longer make an additional request.

Before:

const hooks = require('feathers-authentication-hooks');

app.service('messages').before({
  remove: [
    hooks.restrictToOwner({ idField: 'id', ownerField: 'sentBy' })
  ]
});

Now:

const { setField } = require('feathers-authentication-hooks');

app.service('messages').before({
  remove: [
    setField({
      from: 'params.user.id',
      as: 'params.query.userId'
    })
  ]
});

associateCurrentUser

The associateCurrentUser can also be replaced by setField by setting data instead of params.query.*

Before:

const hooks = require('feathers-authentication-hooks');

app.service('messages').before({
  create: [
    hooks.associateCurrentUser({ idField: 'id', as: 'sentBy' })
  ]
});

Now:

const { setField } = require('feathers-authentication-hooks');

app.service('messages').before({
  create: [
    setField({
      from: 'params.user.id',
      as: 'data.sentBy'
    })
  ]
});

License

Copyright (c) 2019

Licensed under the MIT license.