• Stars
    star
    1,167
  • Rank 38,628 (Top 0.8 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 11 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Passport-Local Mongoose is a Mongoose plugin that simplifies building username and password login with Passport

Passport-Local Mongoose

Passport-Local Mongoose is a Mongoose plugin that simplifies building username and password login with Passport.

Node.js CI Coverage Status

Tutorials

Michael Herman gives a comprehensible walk through for setting up mongoose, passport, passport-local and passport-local-mongoose for user authentication in his blog post User Authentication With Passport.js

Installation

> npm install passport-local-mongoose

Passport-Local Mongoose does not require passport or mongoose dependencies directly but expects you to have these dependencies installed.

In case you need to install the whole set of dependencies

> npm install passport mongoose passport-local-mongoose

Usage

Plugin Passport-Local Mongoose

First you need to plugin Passport-Local Mongoose into your User schema

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const passportLocalMongoose = require('passport-local-mongoose');

const User = new Schema({});

User.plugin(passportLocalMongoose);

module.exports = mongoose.model('User', User);

You're free to define your User how you like. Passport-Local Mongoose will add a username, hash and salt field to store the username, the hashed password and the salt value.

Additionally, Passport-Local Mongoose adds some methods to your Schema. See the API Documentation section for more details.

Configure Passport/Passport-Local

You should configure Passport/Passport-Local as described in the Passport Guide.

Passport-Local Mongoose supports this setup by implementing a LocalStrategy and serializeUser/deserializeUser functions.

To setup Passport-Local Mongoose use this code

// requires the model with Passport-Local Mongoose plugged in
const User = require('./models/user');

// use static authenticate method of model in LocalStrategy
passport.use(new LocalStrategy(User.authenticate()));

// use static serialize and deserialize of model for passport session support
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

Make sure that you have mongoose connected to mongodb and you're done.

Simplified Passport/Passport-Local Configuration

Starting from version 0.2.1, passport-local-mongoose adds a helper method createStrategy as static method to your schema. The createStrategy is responsible to setup passport-local LocalStrategy with the correct options.

const User = require('./models/user');

// CHANGE: USE "createStrategy" INSTEAD OF "authenticate"
passport.use(User.createStrategy());

passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

The reason for this functionality is that when using the usernameField option to specify an alternative usernameField name, for example "email" passport-local would still expect your frontend login form to contain an input field with name "username" instead of email. This can be configured for passport-local but this is double the work. So we got this shortcut implemented.

Async/Await

Starting from version 5.0.0, passport-local-mongoose is async/await enabled by returning Promises for all instance and static methods except serializeUser and deserializeUser.

const user = new DefaultUser({username: 'user'});
await user.setPassword('password');
await user.save();
const { user } = await DefaultUser.authenticate()('user', 'password');

Options

When plugging in Passport-Local Mongoose plugin, additional options can be provided to configure the hashing algorithm.

User.plugin(passportLocalMongoose, options);

Main Options

  • saltlen: specifies the salt length in bytes. Default: 32
  • iterations: specifies the number of iterations used in pbkdf2 hashing algorithm. Default: 25000
  • keylen: specifies the length in byte of the generated key. Default: 512
  • digestAlgorithm: specifies the pbkdf2 digest algorithm. Default: sha256. (get a list of supported algorithms with crypto.getHashes())
  • interval: specifies the interval in milliseconds between login attempts, which increases exponentially based on the number of failed attempts, up to maxInterval. Default: 100
  • maxInterval: specifies the maximum amount of time an account can be locked. Default 300000 (5 minutes)
  • usernameField: specifies the field name that holds the username. Defaults to 'username'. This option can be used if you want to use a different field to hold the username for example "email".
  • usernameUnique: specifies if the username field should be enforced to be unique by a mongodb index or not. Defaults to true.
  • saltField: specifies the field name that holds the salt value. Defaults to 'salt'.
  • hashField: specifies the field name that holds the password hash value. Defaults to 'hash'.
  • attemptsField: specifies the field name that holds the number of login failures since the last successful login. Defaults to 'attempts'.
  • lastLoginField: specifies the field name that holds the timestamp of the last login attempt. Defaults to 'last'.
  • selectFields: specifies the fields of the model to be selected from mongodb (and stored in the session). Defaults to 'undefined' so that all fields of the model are selected.
  • usernameCaseInsensitive: specifies the usernames to be case insensitive. Defaults to 'false'.
  • usernameLowerCase: convert username field value to lower case when saving an querying. Defaults to 'false'.
  • populateFields: specifies fields to populate in findByUsername function. Defaults to 'undefined'.
  • encoding: specifies the encoding the generated salt and hash will be stored in. Defaults to 'hex'.
  • limitAttempts: specifies whether login attempts should be limited and login failures should be penalized. Default: false.
  • maxAttempts: specifies the maximum number of failed attempts allowed before preventing login. Default: Infinity.
  • unlockInterval: specifies the interval in milliseconds, which is for unlock user automatically after the interval is reached. Defaults to 'undefined' which means deactivated.
  • passwordValidator: specifies your custom validation function for the password in the form:
    passwordValidator = function(password,cb) {
      if (someValidationErrorExists(password)) {
        return cb('this is my custom validation error message')
      }
      // return an empty cb() on success
      return cb()
    }
    Default: validates non-empty passwords.
  • passwordValidatorAsync: specifies your custom validation function for the password with promises in the form:
    passwordValidatorAsync = function(password) {
      return someAsyncValidation(password)
        .catch(function(err){
          return Promise.reject(err)
        })
    }
  • usernameQueryFields: specifies alternative fields of the model for identifying a user (e.g. email).
  • findByUsername: Specifies a query function that is executed with query parameters to restrict the query with extra query parameters. For example query only users with field "active" set to true. Default: function(model, queryParameters) { return model.findOne(queryParameters); }. See the examples section for a use case.

Attention! Changing any of the hashing options (saltlen, iterations or keylen) in a production environment will prevent existing users from authenticating!

Error Messages

Override default error messages by setting options.errorMessages.

  • MissingPasswordError: 'No password was given'
  • AttemptTooSoonError: 'Account is currently locked. Try again later'
  • TooManyAttemptsError: 'Account locked due to too many failed login attempts'
  • NoSaltValueStoredError: 'Authentication not possible. No salt value stored'
  • IncorrectPasswordError: 'Password or username are incorrect'
  • IncorrectUsernameError: 'Password or username are incorrect'
  • MissingUsernameError: 'No username was given'
  • UserExistsError: 'A user with the given username is already registered'

Hash Algorithm

Passport-Local Mongoose use the pbkdf2 algorithm of the node crypto library. Pbkdf2 was chosen because platform independent (in contrary to bcrypt). For every user a generated salt value is saved to make rainbow table attacks even harder.

Examples

For a complete example implementing a registration, login and logout see the login example.

API Documentation

Instance methods

setPassword(password, [cb])

Sets a user password. Does not save the user object. If no callback cb is provided a Promise is returned.

changePassword(oldPassword, newPassword, [cb])

Changes a user's password hash and salt, resets the user's number of failed password attempts and saves the user object (everything only if oldPassword is correct). If no callback cb is provided a Promise is returned. If oldPassword does not match the user's old password, an IncorrectPasswordError is passed to cb or the Promise is rejected.

authenticate(password, [cb])

Authenticates a user object. If no callback cb is provided a Promise is returned.

resetAttempts([cb])

Resets a user's number of failed password attempts and saves the user object. If no callback cb is provided a Promise is returned. This method is only defined if options.limitAttempts is true.

Callback Arguments

  • err
    • null unless the hashing algorithm throws an error
  • thisModel
    • the model getting authenticated if authentication was successful otherwise false
  • passwordErr
    • an instance of AuthenticationError describing the reason the password failed, else undefined.

Using setPassword() will only update the document's password fields, but will not save the document. To commit the changed document, remember to use Mongoose's document.save() after using setPassword().

Error Handling

  • IncorrectPasswordError: specifies the error message returned when the password is incorrect. Defaults to 'Incorrect password'.
  • IncorrectUsernameError: specifies the error message returned when the username is incorrect. Defaults to 'Incorrect username'.
  • MissingUsernameError: specifies the error message returned when the username has not been set during registration. Defaults to 'Field %s is not set'.
  • MissingPasswordError: specifies the error message returned when the password has not been set during registration. Defaults to 'Password argument not set!'.
  • UserExistsError: specifies the error message returned when the user already exists during registration. Defaults to 'User already exists with name %s'.
  • NoSaltValueStored: Occurs in case no salt value is stored in the MongoDB collection.
  • AttemptTooSoonError: Occurs if the option limitAttempts is set to true and a login attept occures while the user is still penalized.
  • TooManyAttemptsError: Returned when the user's account is locked due to too many failed login attempts.

All those errors inherit from AuthenticationError, if you need a more general error class for checking.

Static methods

Static methods are exposed on the model constructor. For example to use createStrategy function use

const User = require('./models/user');
User.createStrategy();
  • authenticate() Generates a function that is used in Passport's LocalStrategy
  • serializeUser() Generates a function that is used by Passport to serialize users into the session
  • deserializeUser() Generates a function that is used by Passport to deserialize users into the session
  • register(user, password, cb) Convenience method to register a new user instance with a given password. Checks if username is unique. See login example.
  • findByUsername() Convenience method to find a user instance by it's unique username.
  • createStrategy() Creates a configured passport-local LocalStrategy instance that can be used in passport.

Examples

Allow only "active" users to authenticate

First, we define a schema with an additional field active of type Boolean.

const UserSchema = new Schema({
  active: Boolean
});

When plugging in Passport-Local Mongoose, we set usernameUnique to avoid creating a unique mongodb index on field username. To avoid non active users being queried by mongodb, we can specify the option findByUsername that allows us to restrict a query. In our case we want to restrict the query to only query users with field active set to true. The findByUsername MUST return a Mongoose query.

UserSchema.plugin(passportLocalMongoose, {
  // Set usernameUnique to false to avoid a mongodb index on the username column!
  usernameUnique: false,

  findByUsername: function(model, queryParameters) {
    // Add additional query parameter - AND condition - active: true
    queryParameters.active = true;
    return model.findOne(queryParameters);
  }
});

To test the implementation, we can simply create (register) a user with field active set to false and try to authenticate this user in a second step:

const User = mongoose.model('Users', UserSchema);

User.register({username:'username', active: false}, 'password', function(err, user) {
  if (err) { ... }

  const authenticate = User.authenticate();
  authenticate('username', 'password', function(err, result) {
    if (err) { ... }

    // Value 'result' is set to false. The user could not be authenticated since the user is not active
  });
});

Updating from 1.x to 2.x

The default digest algorithm was changed due to security implications from sha1 to sha256. If you decide to upgrade a production system from 1.x to 2.x, your users will not be able to login since the digest algorithm was changed! In these cases plan some migration strategy and/or use the sha1 option for the digest algorithm.

License

Passport-Local Mongoose is licensed under the MIT license.

More Repositories

1

mongoose-version

Mongoose plugin to save document data versions. Documents are saved to a "versioned" document collection before saving original documents and kept for later use.
JavaScript
144
star
2

restify-mongoose

Restify-Mongoose provides a resource abstraction to expose mongoose models as REST resources.
JavaScript
110
star
3

microq

Micro job queue built on mongo
JavaScript
65
star
4

keepasschrome

CSS
27
star
5

bumm

Opinionated project generator for node.js relying on express and mongoose. The bumm repository moved to https://github.com/the-diamond-dogs-group-oss/bumm
JavaScript
22
star
6

toggl-client

Client for the Toggl API built for async and await support
JavaScript
13
star
7

express-upload

Chainable file upload api for express
JavaScript
11
star
8

prettiertestlogger

Prettier formatting for your dotnet core tests.
C#
10
star
9

passport-local-authenticate

Encapsulates methods used to hash and verify user credentials for use in a passport-local strategy.
JavaScript
7
star
10

miniops

MiniOps is a dependency free in memory operations monitor and dashboard
HTML
6
star
11

CommonExtensionMethods

Common c# extension methods used in my projects
C#
6
star
12

estools

Provides a set of utility function to traverse, filter and map esprima ASTs
JavaScript
6
star
13

express-req-metrics

Express middleware to collect request metrics and pass request metrics to a processing function.
JavaScript
5
star
14

irc-repl

IRC + REPL => ❤️
JavaScript
4
star
15

tinify-cli

Tinify images from the command line using the tinify API
JavaScript
4
star
16

generaterr

A simple custom error generator for node.js
JavaScript
4
star
17

betray

Minimal test spies, stubs and mocks module for node.js
JavaScript
3
star
18

Piwik-Tracking

Piwik tracking for Silverlight
C#
3
star
19

resistor

Resist mass assignment vulnerabilities - map the important bits
JavaScript
2
star
20

template-url

Super simple no fluff rest URL style formatting for node.
JavaScript
2
star
21

streets-austria

JSON data containing valid streets in Austria
JavaScript
2
star
22

testeroid

dotnet test on steroids
C#
2
star
23

amqp-jobs

Minimalist abstraction layer for amqp jobs implementations
JavaScript
2
star
24

everything-nodejs

Everything Node.js Talk
JavaScript
2
star
25

deploygirl

Low ceremony super hero application deployment
JavaScript
2
star
26

parkbench

Benchmark like a pro
JavaScript
2
star
27

pixoo-soup

Display a soup of pixels on your Divoom Pixoo. Should work on other Divoom devices as well.
JavaScript
2
star
28

remarkedupjs

Remarkedup generates HTML using customizable templates from markdown adding features such as (hopefully) nice typography and table of contents.
JavaScript
2
star
29

git-visit

Git command line wrapping library to git visit commit history
JavaScript
2
star
30

metalsmith-tinify

A metalsmith plugin to compress images uning the tinify API
JavaScript
2
star
31

metalsmith-canonical

A metalsmith plugin to add a canonical url property to pages
JavaScript
2
star
32

drop-mongodb-collections

Drops all (non system) mongodb collections
JavaScript
2
star
33

RemarkedUp

C#
1
star
34

isci

Detect if builds or tests are running in a CI environment
C#
1
star
35

togglog-cli

Command line utility to log time entries and more using toggl
JavaScript
1
star
36

remorseless

Retry failed functions
JavaScript
1
star
37

test-hooks

Just a small repo to trigger github hooks
1
star
38

groomish

Micro ORM for Postgres
TypeScript
1
star
39

mongojs-paginate

Query pagination helper for mongojs
JavaScript
1
star
40

node-proxy-sandbox

JavaScript
1
star
41

presentation-nock

Nock presentation node.js vienna
JavaScript
1
star
42

Interceptable-Validators

This small javascript library adds the possibility to intercept validation in ASP.NET
ASP
1
star
43

npm-download-hamster

Provide useful statistics on npm package downloads
JavaScript
1
star
44

bmp180-sensor

An Node.js module to interface a BMP085 and BMP180 temperature and pressure sensor with the Raspberry Pi
JavaScript
1
star
45

amqp-pubsub

Minimalist abstraction layer for amqp publish/subscribe implementations
JavaScript
1
star
46

generative-art-experiments

Generative art experiments powered by vite and svg.js plus some superpowers from the npm ecosystem
JavaScript
1
star