Skip to content

Flexible authentication solution for nodejs and mongodb

License

Notifications You must be signed in to change notification settings

kasongoyo/jabali

Repository files navigation

Jabali

Coverage Status Conventional Commits

Jabali is the mongoose plugin used as the flexible authentication solution. Jabali when plugged into mongoose schema, it extends the schema with some fields based on OpenID connect specification.

Modules

Jabali is organized on modularity architecture. Jabali modules consists of;

  • Registerable Module responsible for user sign up.
  • Authenticable Module to handle authentication flow.
  • Confirmable Module responsible to manage email or phone confirmation.
  • Recoverable Module responsible for resetting account password

Features

  • User signup
  • User login using email, phone number or any other preferred user field together with password. See aliases options
  • Email and phone number validation
  • Password validation using configurable policies such as minimum length, presence of number, capital letter etc
  • Account confirmation work flow using email or phone number(You need to have your own setup to send token to phone or email)
  • Password reset work flow
  • Ability to configure time period to allow user to access resources without account confirmation. After the period expired user will not be able to authenticate without account confirmation.

Prerequisites

Installing

npm i --save jabali

Usage

Sample example

const jabali = require('jabali')

// user schema
const UserSchema = new Schema({
   ...
})

// plugin jabali default module
UserSchema.plugin(jabali, options)

// register user schema
mongoose.model('User', UserSchema)

Options

Jabali's options can be declared as an object with key names corresponding to modules and key values equal to object contain options of the specified module. Below are the options available in each module.

Registerable

  • email_required {Boolean} - set if email is required.
  • phone_required {Boolean} - set if phone is required.
  • password_policies {Object} - Object with password policies
  • password_policies.min_length {Number} - Set the minimum number of character passwor should have
  • password_policies.number {Boolean} - Set if atleast one number should be present in the password
  • password_policies.lowercase {Boolean} - Set if atleast one lowercase character should be present in password
  • password_policies.uppercase {Boolean} - Set if atleast one uppercase character should be present in password

Authenticable

  • aliases {String[]} - an array of fields names to use together with password for authentication. Example ['email', 'employeeId'], this will allow to authenticate using email or employeedId as username. EmployeeId is user schema defined field not specific for jabali. Email field is the default field for authentication

Confirmable

  • token_life {Number} - Number of days it will take before confirmation token expire. Default is 1 day
  • allow_unconfirmed_access_for {Number} - Number of days to allow user to authenticate and use the resource before confirming the account. If it is set to zero it means user will not be allowed to authenticate at all before confirming the account. The default is zero

Recoverable

Options

  • token_life {Number} - Number of days it will take before recoverable token expire. Default is 1 day.
  • aliases {String[]} - Array of field names to use during password reset.

Sample example

const jabali = require('jabali')

// user schema
const UserSchema = new Schema({
   ...
})
const options = {
   // options for authenticable module
   authenticable:{
     aliases: ['email']
   },
   // options for confirmable module
   confirmable: {
      token_life: 7
   }
}
// plugin jabali default module
UserSchema.plugin(jabali, options)

// register user schema
mongoose.model('User', UserSchema)

API

  • Model.register(payload) - It register an account, the different between this method and normal mongoose create method is the fact that this method register user and set password and other fields as per jabali specification.
  • Model.unregister(criteria) - It unregister account
  • Model.authenticate(alias, password)
  • Instance.changePassword(newPassword)
  • Model.confirm(username, confirmationToken) - It calls account confirmation, username can either be email or phone number
  • Model.sendConfirmationInstructions(username) - It send out account confirmtion instructions.
  • Instance.sendConfirmationInstructions - It send out account confirmtion instructions.
  • Model.passwordReset(alias, newPassword, recoveryToken) - It reset password
  • Instance.sendPasswordResetInstructions() - It send out password reset instructions.

Account Confirmation Instructions

By default, account/user registeration action automatically send account confirmation instructions. This behaviour can be disabled per user instance if autoSendConfirmationInstructions user property is set to false. When set to false, you will need to send confirmation instructions manual by calling static method Model.sendConfirmationInstructions(username).

Hooks

Jabali also support hooks which are functions used to add custom behaviours prior or post certain actions as follows;

sendJabaliNotification

This is the hook that is triggered post certain events that requires user to be notified such as on password reset request and other event as explained below. This function when called, will be passed two parameters, the first parameter will be event/notification type and the second parameter will be an accompanied event data.

Notification types so far includes but not limited to the followings;

  • CONFIRMATION_INSTRUCTIONS - Triggered during user registration or when calling sendConfirmationInstructions method. An accompanied data will be schema instance
  • PASSWORD_RESET_INSTRUCTIONS - Triggered when password reset is executed. An accompanied data will be schema instance

Note
This function must return promise and should never reject if you don't want notification to affect the prior action that triggered the notification send**. If failure of notification should roll back the prior actions then you can actual reject the promise otherwise always resolve the promise.

Example

schema.methods.sendJabaliNotification = function(NOTIFICATION_TYPE, instance){
   if(NOTIFICATION_TYPE === 'CONFIRMATION_INSTRUCTIONS'){
      return Mailer
      .sendEmail(instance.email, instance.confirmationToken)
      .catch(error => {
         // Always resolve because this notification should not roll
         // back registration action which triggered it.
         return Promise.resolve();
      })
   }
    return Promise.resolve();
}

preSignup

This schema instance method will be triggered prior to user signup/registration and It must return this instance otherwise it break registeration. It can be used forexample to automatically confirm user from a particular domain as follows;

Example

schema.methods.preSignup = function(){
   const user = this;
   const addresses = user.email.split('@');
   if(/mydomain/i.test(addresses[1])){
      user.autoConfirm = true;
   }
   return user;
}

Note:
All hooks must be defined after this plugin is attached to the schema for them to be active.

Testing

  • Clone this repository

  • Install all development dependencies

$ npm install
  • Then run test
$ npm test

Built With

  • npm - Used as the project core technology and build tool

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

Authors

  • Isaac Kasongoyo - Initial work

License

This project is licensed under the MIT License - see the LICENSE.md file for details

Acknowledgments

The code and some of the concepts of this project has been inspired by the following libraries

About

Flexible authentication solution for nodejs and mongodb

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •