Beginning Node.js – local authentication with Passport-Local Mongoose – part 6

Disclaimer: This is a series about me, creating a web application in Node.js. The completed example is available here.

I have a deep respect for all those developers out there that write fantastic modules I can use in my projects. One little gem is passport-local-mongoose. I’ve written about it before but as you see I’m doing it again.

What is passport-local-mongoose?

You can plug-in passport-local-mongoose into your Mongoose Userschema. This decorates the User object with a set of methods. E.g.

  • authenticate
  • register
  • setPassword
  • serialize
  • deserialize

It also hashes the passwords. This saves a lot of work.

What we should work on

  • Users should be able to register
  • Users should be able to authenticate
  • Users should be able to change their password
  • Users should be able to change their e-mail address
  • There should be a ‘forgot password’ procedure
  • Users should be able to delete their accounts

This article covers only ‘register’ and ‘authenticate’. You can go ahead and clone the restaurant github repo for a full example.

To add local authentication to your app you’ll need to run:

Of course, you may add your own properties to the model:

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

var User = new Schema({
    uuid: {
        type: String,
        required: false
    },
    firstname: {
        type: String,
        required: true
    },
    active: {
        type: String,
        required: false
    }
});

var options = ({missingPasswordError: "Wrong password"});
User.plugin(passportLocalMongoose,options);

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

Now let’s hook up Passport in our app.

Controller

Let’s create a user controller which contains the register, the login and the getLogin functions (to check if a user has logged in).
Create a file named controller.user.js and put it in the app folder:

var mongoose = require('mongoose');
var User = require('./model.user');

exports.register = function (req, res) {
    console.log("registering: " + req.body.firstName);
    User.register(new User({
        username: req.body.username,
        firstname: req.body.firstname
    }), req.body.password, function (err, user) {
        if (err) {
            console.log(err);
            return res.send(err);
        } else {
            res.send({
                success: true,
                user: user
            });
        }
    });
};

exports.login = function (req, res, next) {

    User.authenticate()(req.body.username, req.body.password, function (err, user, options) {
        if (err) return next(err);
        if (user === false) {
            res.send({
                message: options.message,
                success: false
            });
        } else {
            req.login(user, function (err) {
                res.send({
                    success: true,
                    user: user
                });
            });
        }
    });

};

exports.getLogin = function (req, res) {
    console.log(req.user);
    if (req.user) {

        return res.send({
            success: true,
            user: req.user
        });

    } //res.send(500, {status:500, message: 'internal error', type:'internal'}); == deprecated


    res.send({
        success: false,
        message: 'not authorized'
    });
};

What happens?
1. User.authenticate and User.register:
The User.authenticate and User.register are functions we get from passport-local-mongoose. I just took this code as an example.

2. Check if a user is logged in with ‘if(req.user)’
If a user is logged in, the req.user property is populated with the user object.
So if it exists, the user is logged in.

Routes

//mongodb
var mongoose = require('mongoose');
var User = require('./model.user');

var users = require('./controller.user');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var cookieParser = require('cookie-parser');
var session = require('express-session');


module.exports = function (app) {

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

    //need this according to passport guide
    app.use(cookieParser());
    app.use(session({
        secret: 'the princess and the frog',
        saveUninitialized: true,
        resave: true
    }));
    app.use(passport.initialize());
    app.use(passport.session());

    //routes
    app.route('/register').post(users.register);
    app.route('/login').post(users.login);
    app.route('/login').get(users.getlogin);
   
   
};

Add this file to main.js, like so:

require('./app/routes.user')(app);

This will be your completed main.js:

var express = require('express');
var app = express();
var bodyparser = require('body-parser');
var mongoose = require('mongoose');

app.use(bodyparser.urlencoded({
  extended: true
}));

app.use(bodyparser.json());

mongoose.connect('mongodb://localhost:27017/restaurant');

require('./app/routes.food')(app);
require('./app/routes.user')(app);

app.use(express.static(__dirname + '/public'));

app.set('port', process.env.PORT || 3001);
app.listen(app.get('port'));
console.log("the server is running on http://localhost:" + app.get('port'));

Let’s try this

Install Postman or another REST API test tool.

  • Don’t forget to configure the headers: Content-Type application/json

First, let’s register a user (click POST):

Postman_passport

Second, let’s login:

Selection_012

Check the login status:

Selection_015

The end of this series

This is where this series end. I hope anyone will enjoy this and at least learns something from my struggles. I know I did!
Your feedback is more than welcome by the way.

One Reply to “Beginning Node.js – local authentication with Passport-Local Mongoose – part 6”

  • Hello Jaqueline and thank you for the useful article! I have the following question, I see in your github repo (https://github.com/jacqinthebox/Restaurant/blob/master/app/controller.user.js) how you use the setPassword method of passport-local-mongoose. My question is how to I create a password change form, where a user would submit in the same form his old password and his new one. Obviously for this to work I would have to check his old password to see that it matches to the one already in the database and if it matched I would update his password using the setPassword method, my question is what is the optimal way taking into account security issues, to implement this first step (password comparison).

Laat een reactie achter op Nick Papasavvas Reactie annuleren

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

%d bloggers liken dit: