Passport-Local Mongoose is a Mongoose plugin that simplifies building username and password login with Passport.
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
$ npm install passport-local-mongoose
Passport-Local Mongoose does not require passport
, passport-local
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 passport-local mongoose passport-local-mongoose --save
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.
First you need to plugin Passport-Local Mongoose into your User schema
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
passportLocalMongoose = require('passport-local-mongoose');
var 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.
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
var 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 a mongoose connected to mongodb and you're done.
Starting with 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.
var 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.
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. Default: 100
- 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.
- 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.
- passwordValidator: specifies your custom validation function for the password in the form 'function(password,cb)'. Default: validates non-empty passwords.
- usernameQueryFields: specifies alternative fields of the model for identifying a user (e.g. email).
Attention! Changing any of the hashing options (saltlen, iterations or keylen) in a production environment will prevent that existing users to authenticate!
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'
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.
For a complete example implementing a registration, login and logout see the login example.
asynchronous method to set a user's password hash and salt
asynchronous method to authenticate a user instance
asynchronous method to reset a user's number of failed password attempts (only defined if options.limitAttempts
is true)
callback arguments
- err
- null unless the hasing 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.
- an instance of
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 optionlimitAttempts
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 are exposed on the model constructor. For example to use createStrategy function use
var 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.
Passport-Local Mongoose is licenses under the MIT license.