Skip to content

Configuration

The feathers-authentication-management service is configured at several positions of a Feathers application:

  1. Attaching of the service with options to the Feathers app.

  2. Extension of the user model with new fields required by the service.

  3. Extension of the create hooks in the users service.

  4. Implementation of a custom notifier function to send e-mails, SMS, or use any other communication channel configured in your application.

Service Options

The feathers-authentication-management service is added to the Feathers app with

js
const {
  AuthenticationManagementService,
} = require("feathers-authentication-management");

app.use("/auth-management", new AuthenticationManagementService(app, options));
const {
  AuthenticationManagementService,
} = require("feathers-authentication-management");

app.use("/auth-management", new AuthenticationManagementService(app, options));

Possible options are:

FieldField TypeDescription
servicestringThe path of the service for user items, e.g. /users (default) or /organization.
skipIsVerifiedCheckbooleanIf false (default) it is impossible to reset passwords even if e-mail is not verified.
sanitizeUserForClientUser objectBy default, THE USER OBJECT IS IN THE RESPONSE e. g. of a password reset request. To reply with empty object use sanitizeUserForClient: () => ({}).
notifierfunction(type, user, notifierOptions)Returns a Promise with the notifier function.
longTokenLennumberHalf the length of the long token. Default is 15, giving tokens of 30 characters length.
shortTokenLennumberLength of short token (default: 6).
shortTokenDigitsbooleanIf true (default) short tokens contain only digits. Otherwise also characters.
delaynumberLifetime for e-mail verification tokens in ms. Default is 5*24*60*60*1000 = 432000000 (5 days).
resetDelaynumberLifetime for password reset tokens in ms. Default is 2*60*60*1000 = 7200000 (2 hours).
resetAttemptsnumberAmount of times a user can submit an invalid token before the current token gets removed from the database. Default is 0.
reuseResetTokenbooleanUse the same reset token if the user resets password twice in a short period. In this case token is not hashed in the database. Default is false.
identifyUserPropsstringProperty names in the user item which uniquely identify the user, e.g. ['username', 'email', 'cellphone']. The default is ['email']. Only these properties may be changed with verification by the service. At least one of these properties must be provided whenever a short token is used, as the short token alone is too susceptible to brute force attack.
passwordFieldstringProperty name of the password field. Default is password.
passParams(params) => ParamsPass params from the f-a-m service to /users service.

User Model Fields

The user model has to be extended with new fields that are used by feathers-authentication-management. Not all of these fields are required. Which fields are necessary depend strongly on your use case and the communication channel. Possible fields are:

FieldField TypeDescription
isVerifiedbooleanIndicates if the user's e-mail address has been verified.
verifyTokenstringA long verification token generated for verification e-mails.
verifyShortTokenstringA short verification token generated e. g. for verification SMS.
verifyExpiresDate | numberExpiration date of the verification token.
verifyChangesstring[]An array that tracks e. g. the change of an e-mail address.
resetTokenstringA long reset token generated for password reset e-mails.
resetShortTokenstringA short reset token generated e. g. for password reset SMS.
resetExpiresDate | numberExpiration date of the reset token.
resetAttemptsnumberAmount of incorrect reset submissions left before token invalidation.

All necessary fields have to be added to the users database table and to the users model as well.

Service Hooks

The feathers-authentication-management service does not handle creation of a new user account nor the sending of the initial sign up verification notification. Instead hooks are provided to be used with the users service create method. If you set a service path other than the default of '/auth-management', the custom path name must be passed into the hook.

addVerification

This hook is made exclusively for the /users service. Creates tokens and sets default authManagement data for users.

beforeaftermethodsmultidetails
yesnocreate, patch, updateyessource
  • Arguments:
    • path?: string
ArgumentTypeDefaultDescription
pathstringauthManagementThe service path for the authManagement service.
  • Example:
javascript
// src/services/users/users.hooks.js
const { 
  hashPassword, 
  protect 
} = require("@feathersjs/authentication-local").hooks;
const { 
  addVerification, 
  removeVerification 
} = require("feathers-authentication-management");
const authNotifier = require("path-to/notifier");

const {
  disallow,
  iff,
  isProvider,
  preventChanges,
} = require("feathers-hooks-common");

const sendVerify = () => {
  return (context) => {
    const notifier = authNotifier(context.app);

    const users = Array.isArray(context.result) 
      ? context.result
      : [context.result];

    // Send an e-mail/SMS with the verification token
    await Promise.all(
      users.map(async user => notifier("resendVerifySignup", user))
    )
  };
}

module.exports = {
  before: {
    all: [],
    find: [authenticate("jwt")],
    get: [authenticate("jwt")],
    create: [
      // authenticate("jwt") // enable this, if you have a closed app
      hashPassword("password"),
      addVerification("auth-management"), // adds .isVerified, .verifyExpires, .verifyToken, .verifyChanges
    ],
    update: [
      disallow("external"),
      authenticate("jwt"),
      hashPassword("password"),
    ],
    patch: [
      authenticate("jwt"),
      iff(
        isProvider("external"),
        preventChanges(
          true,
          "email",
          "isVerified",
          "resetExpires"
          "resetShortToken",
          "resetToken",
          "verifyChanges",
          "verifyExpires",
          "verifyShortToken",
          "verifyToken",
        ),
        hashPassword("password")
      ),
    ],
    remove: [authenticate("jwt"), hashPassword("password")],
  },
  after: {
    all: [],
    find: [protect("password")],
    get: [protect("password")],
    create: [
      protect("password"),
      sendVerify(),
      removeVerification(), // removes verification/reset fields other than .isVerified from the response
    ],
    update: [protect("password")],
    patch: [protect("password")],
    remove: [protect("password")],
  },
  error: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: [],
  },
};
// src/services/users/users.hooks.js
const { 
  hashPassword, 
  protect 
} = require("@feathersjs/authentication-local").hooks;
const { 
  addVerification, 
  removeVerification 
} = require("feathers-authentication-management");
const authNotifier = require("path-to/notifier");

const {
  disallow,
  iff,
  isProvider,
  preventChanges,
} = require("feathers-hooks-common");

const sendVerify = () => {
  return (context) => {
    const notifier = authNotifier(context.app);

    const users = Array.isArray(context.result) 
      ? context.result
      : [context.result];

    // Send an e-mail/SMS with the verification token
    await Promise.all(
      users.map(async user => notifier("resendVerifySignup", user))
    )
  };
}

module.exports = {
  before: {
    all: [],
    find: [authenticate("jwt")],
    get: [authenticate("jwt")],
    create: [
      // authenticate("jwt") // enable this, if you have a closed app
      hashPassword("password"),
      addVerification("auth-management"), // adds .isVerified, .verifyExpires, .verifyToken, .verifyChanges
    ],
    update: [
      disallow("external"),
      authenticate("jwt"),
      hashPassword("password"),
    ],
    patch: [
      authenticate("jwt"),
      iff(
        isProvider("external"),
        preventChanges(
          true,
          "email",
          "isVerified",
          "resetExpires"
          "resetShortToken",
          "resetToken",
          "verifyChanges",
          "verifyExpires",
          "verifyShortToken",
          "verifyToken",
        ),
        hashPassword("password")
      ),
    ],
    remove: [authenticate("jwt"), hashPassword("password")],
  },
  after: {
    all: [],
    find: [protect("password")],
    get: [protect("password")],
    create: [
      protect("password"),
      sendVerify(),
      removeVerification(), // removes verification/reset fields other than .isVerified from the response
    ],
    update: [protect("password")],
    patch: [protect("password")],
    remove: [protect("password")],
  },
  error: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: [],
  },
};

isVerified

Throws, if requesting user is not verified (params.user.isVerified) and passes otherwise.

beforeaftermethodsmultidetails
yesnoallyessource
  • Arguments:

    • none
  • Example:

js
const { authenticate } = require("@feathersjs/authentication").hooks;
const { isVerified } = require("feathers-authentication-management");

module.exports = {
  before: {
    all: [authenticate("jwt"), isVerified()],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: [],
  },
  after: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: [],
  },
  error: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: [],
  },
};
const { authenticate } = require("@feathersjs/authentication").hooks;
const { isVerified } = require("feathers-authentication-management");

module.exports = {
  before: {
    all: [authenticate("jwt"), isVerified()],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: [],
  },
  after: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: [],
  },
  error: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: [],
  },
};

removeVerification

This hook is made exclusively for the /users service. It deletes data on user items for external requests that was added for feathers-authentication-management to work. It is similar to the protect('password') hook from @feathersjs/authentication-local. It deletes verifyExpires, resetExpires and verifyChanges and if ifReturnToken: true it also deletes verifyToken, verifyShortToken, resetToken and resetShortToken.

beforeaftermethodsmultidetails
noyesallyessource
  • Arguments:
    • ifReturnToken?: boolean
ArgumentTypeDefaultDescription
ifReturnTokenbooleanfalseremoves

Notifier Function

The notifier function is passed to feathers-authentication-management as a parameter. It handles the sending of any notification depending on the action.

It returns a Promise and is called with three parameters:

  • type: the name of the action:

    • resendVerifySignup from resendVerifySignup API call
    • verifySignup from verifySignupLong and verifySignupShort API calls
    • verifySignupSetPassword from verifySignupSetPasswordLong and verifySignupSetPasswordShort API calls
    • sendResetPwd from sendResetPwd API call
    • resetPwd from resetPwdLong and resetPwdShort API calls
    • passwordChange from passwordChange API call
    • identityChange from identityChange API call
  • user: the user object, containing information such as user name or e-mail address.

  • notifierOptions: notifierOptions option from resendVerifySignup and sendResetPwd API calls

Released under the MIT License.