Authorization Hooks
These hooks come bundled with the Feathers authentication plugin.
Implementing authorization is not automatic, but is easy to set up with the included hooks. You can also create your own hooks to handle your app's custom business logic. For more information about hooks, refer to the chapter on hooks.
The feathers-authentication plug-in includes the following hooks to help with the authorization process. The most common scenario is that you simply want to restrict a service to only authenticated users. That can be done like so:
const hooks = require('feathers-authentication').hooks;
// Must be logged in do anything with messages.
app.service('messages').before({
all: [
hooks.verifyToken(),
hooks.populateUser(),
hooks.restrictToAuthenticated()
]
});
ProTip: All bundled authorization hooks will automatically pull values from your
authconfig. You can override them explicitly by passing them to the hook.
hashPassword
The hashPassword hook will automatically hash the data coming in on the provided passwordField. It is intended to be used as a before hook on the user service for the create, update, or patch methods.
const hooks = require('feathers-authentication').hooks;
app.service('user').before({
create: [
hooks.hashPassword()
]
});
Options
passwordField(default: 'password') [optional] - The field you use to denote the password on your user object.
verifyToken
The verifyToken hook will attempt to verify a token. If the token is missing or is invalid it returns an error. If the token is valid it adds the decrypted payload to hook.params.payload which contains the user id. It is intended to be used as a before hook on any of the service methods.
const hooks = require('feathers-authentication').hooks;
app.service('user').before({
get: [
hooks.verifyToken()
]
});
Options
secret(default: the one from your config) [optional] - Your secret used to encrypt and decrypt JWT's on the server. If this gets compromised you need to rotate it immediately!issuer(default: 'feathers') [optional] - The JWT issuer fieldalgorithm(default: 'HS512') [optional] - The accepted JWT hash algorithmexpiresIn(default: '1d') [optional] - The time a token is valid for
You can view the all available options in the node-jsonwebtoken repo.
verifyOrRestrict
The verifyOrRestrict is intended to be used as a before hook for any service on the find or get methods. The hook will attempt to verify a token. If the token is missing or is invalid it adds a restriction onto the query and calls find with that query. If the token is valid it adds the decrypted payload to hook.params.payload which contains the user id but does not add the restriction.
const hooks = require('feathers-authentication').hooks;
// If the user is not authorized they will only see comments that are approved
const restriction = { approved: true };
app.service('comments').before({
get: [
hooks.verifyOrRestrict({restrict: restriction})
],
find: [
hooks.verifyOrRestrict({restrict: restriction})
],
});
For instance, if the client queries for all comments with a certain number of likes
{ likes: {$gt: 50} }
but are not authenticated, then verifyOrRestrict will merge the restriction into the query.
{ likes: {$gt: 50} , approved: true}
The hook will always call the find method even if a get by id request was made so that if the document being requested was not approved then the query would not succeed.
Options
restrict(default: undefined) [optional] - This is a query object that will merge into and override the query passed from the client.secret(default: the one from your config) [optional] - Your secret used to encrypt and decrypt JWT's on the server. If this gets compromised you need to rotate it immediately!issuer(default: 'feathers') [optional] - The JWT issuer fieldalgorithm(default: 'HS512') [optional] - The accepted JWT hash algorithmexpiresIn(default: '1d') [optional] - The time a token is valid for
You can view the all available options in the node-jsonwebtoken repo.
populateUser
The populateUser hook is for populating a user based on an id. It can be used on any service method as either a before or after hook. It is called internally after a token is created.
const hooks = require('feathers-authentication').hooks;
app.service('user').before({
get: [
hooks.populateUser()
]
});
Options
userEndpoint(default: '/users') [optional] - The endpoint for the user service.idField(default: '_id') [optional] - The database field containing the user id.
populateOrRestrict
The populateOrRestrict hook is for populating a user based on an id. If the user it not found it adds a restriction on the query being passed from the client. It is intended to be used as a before hook for any service on the find or get methods. It is meant to be called after a token is verified.
const hooks = require('feathers-authentication').hooks;
app.service('user').before({
get: [
hooks.verifyOrRestrict({ restrict: {approved: true} }),
hooks.populateOrRestrict({ restrict: {approved: true} })
]
});
Options
restrict(default: undefined) [optional] - The restriction to merge into the queryuserEndpoint(default: '/users') [optional] - The endpoint for the user service.idField(default: '_id') [optional] - The database field containing the user id.
restrictToAuthenticated
The restrictToAuthenticated hook throws an error if there isn't a logged-in user by checking for the hook.params.user object. It can be used on any service method and is intended to be used as a before hook. It doesn't take any arguments.
const hooks = require('feathers-authentication').hooks;
app.service('user').before({
get: [
hooks.restrictToAuthenticated()
]
});
queryWithCurrentUser
The queryWithCurrentUser before hook will automatically add the user's id as a parameter in the query. This is useful when you want to only return data, for example "messages", that were sent by the current user.
const hooks = require('feathers-authentication').hooks;
app.service('messages').before({
find: [
hooks.queryWithCurrentUser({ idField: 'id', as: 'sentBy' })
]
});
Options
idField(default: '_id') [optional] - The id field on your user object.as(default: 'userId') [optional] - The id field for a user on the resource you are requesting.
When using this hook with the default options the User._id will be copied into hook.params.query.userId.
associateCurrentUser
The associateCurrentUser before hook is similar to the queryWithCurrentUser, but works on the incoming data instead of the query params. It's useful for automatically adding the userId to any resource being created. It can be used on create, update, or patch methods.
const hooks = require('feathers-authentication').hooks;
app.service('messages').before({
create: [
hooks.associateCurrentUser({ idField: 'id', as: 'sentBy' })
]
});
Options
idField(default: '_id') [optional] - The id field on your user object.as(default: 'userId') [optional] - The id field for a user that you want to set on your resource.
restrictToOwner
restrictToOwner is meant to be used as a before hook. It only allows the user to retrieve resources that are owned by them. It will return a Forbidden error without the proper permissions. It can be used on get, create, update, patch or remove methods.
const hooks = require('feathers-authentication').hooks;
app.service('messages').before({
remove: [
hooks.restrictToOwner({ idField: 'id', ownerField: 'sentBy' })
]
});
Options
idField(default: '_id') [optional] - The id field on your user object.ownerField(default: 'userId') [optional] - The id field for a user on your resource.
restrictToRoles
restrictToRoles is meant to be used as a before hook. It only allows the user to retrieve resources that are owned by them or protected by certain roles. It will return a Forbidden error without the proper permissions. It can be used on all methods when the owner option is set to 'false'. When the owner option is set to true the hook can only be used on get, update, patch, and remove service methods.
const hooks = require('feathers-authentication').hooks;
app.service('messages').before({
remove: [
hooks.restrictToRoles({
roles: ['admin', 'super-admin'],
fieldName: 'permissions',
idField: 'id',
ownerField: 'sentBy',
owner: true
})
]
});
Options
roles(required) - An array of roles that a user must have at least one of in order to access the resource.fieldName(default: 'roles') [optional] - The field on your user object that denotes their roles.idField(default: '_id') [optional] - The id field on your user object.ownerField(default: 'userId') [optional] - The id field for a user on your resource.owner(default: 'false') [optional] - Denotes whether it should also allow owners regardless of their role (ie. the user has the role or is an owner).
hasRoleOrRestrict
hasRoleOrRestrict is meant to be used as a before hook for any service on the find or get methods. Unless the user has one of the roles provided, it will add a restriction onto the query to limit what resources return.
const hooks = require('feathers-authentication').hooks;
app.service('messages').before({
find: [
hooks.hasRoleOrRestrict({
roles: ['admin', 'super-admin'],
fieldName: 'permissions',
restrict: { approved: true }
})
]
});
Options
roles(required) - An array of roles that a user must have at least one of in order to access the resource.fieldName(default: 'roles') [optional] - The field on your user object that denotes their roles.restrict(default: undefined) - The query to merge into the client query to limit what resources are accessed