Building my own mean framework : a-mean - Part 2

Sabyasachi Patra
4 min readAug 3, 2018

--

TL;DR

In this series of articles we will be building a very basic mean framework with login and registration functionality.

This is the part 2 of that series. If you have missed the part 1. You can check out here. In this post we will be creating login - registration system and authenticate with passport.

Part 2 : Creating authentication in the back-end

1. Install these packages via npm

npm install bcrypt@2.0.1 jsonwebtoken mongoose passport passport-jwt mongoose --save

2. configuring mongodb

i. create a config folder inside server & create a main.js file

mkdir server/config && touch server/config/main.js

ii. put the below code in the main.js file

module.exports = {
"secret":"f122f050696aa0fa2c26c7bb2c7b2a646dc8ee65552fe3f9e49a7a5da21145441b243690e03a2d65",
"database":"mongodb://localhost:27017/my-database"
};

Note : We will be needing the secret key for securing passport (replace the secret key with your own). Replace localhost:27017 with your mongodb host and port, I am using mongodb in localhost on default port. replace my-databasewith your database name.

3. Update app.js with the below code

var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var morgan = require('morgan');
var config = require('./server/config/main');
var passport = require('passport');
var jwt = require('jsonwebtoken');
var mongoose = require('mongoose');

require('./server/config/passport')(passport);

// Create API group routes
var apiRoutes = express.Router();

// Use body-parser to get POST requests for API use
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.use(morgan('dev'));

// Connect to database
mongoose.connect(config.database, { useNewUrlParser: true }, function(err) {
if (err) throw err;
});

app.use(passport.initialize());

//routes
require('./server/routes/routes.js')(apiRoutes);

// Set url for API group routes
app.use('/api', apiRoutes);

module.exports = app;

4. Create user Schema

i. Create a folder models inside server and create user.js file inside models

mkdir server/models && touch server/models/user.js

ii. put the below code in user.js file

var mongoose = require('mongoose');
var bcrypt = require('bcrypt');

var UserSchema = new mongoose.Schema({
email: {
type: String,
lowercase: true,
unique: true,
required: true
},
password: {
type: String,
required: true
},
name: {
type: String,
required: true
},
created_at: {
type: Date,
default: Date.now
},
});

UserSchema.pre('save', function (next) {
var user = this;
if (this.isModified('password') || this.isNew) {
bcrypt.genSalt(10, function (err, salt) {
if (err) {
return next(err);
}
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) {
return next(err);
}
user.password = hash;
next();
});
});
} else {
return next();
}
});

// Create method to compare password input to password saved in database
UserSchema.methods.comparePassword = function(pw, cb) {
bcrypt.compare(pw, this.password, function(err, isMatch) {
if (err) {
return cb(err);
}
cb(null, isMatch);
});
};

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

5. Configuring passport

i. Create passport.js inside the config folder inside server folder

touch server/config/passport.js

ii. put the following in the passport.js file

var JwtStrategy = require('passport-jwt').Strategy;
var ExtractJwt = require('passport-jwt').ExtractJwt;
var User = require('../models/user');
var config = require('./main');

// Setup work and export for the JWT passport strategy
module.exports = function(passport) {
var opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.secret;
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {

User.findOne({_id: jwt_payload._id}, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
return done(null, user);
} else {
return done(null, false);
}
});
}));
};

6. Response beautifier
i. Create a folder helpers inside server and create beautifier.js file inside helpers

mkdir server/helpers && touch server/helpers/beautifier.js

ii. put the following in beautifier.js

'use strict';

exports.beautify = (x,m) => {
const y = {};
y.message = m;
y.data = x;
return y;
}

7. Create userController

i. create a controllers folder inside the server and create userController.js inside the controllers folder

mkdir server/controllerstouch server/controllers/userController.js

ii. put the following content in the userController.js

'use strict';
var User = require('../models/user');
var jwt = require('jsonwebtoken');
var config = require('../config/main');
var jb = require('../helpers/beautifier');

exports.login = function(req, res) {
User.findOne({
email: req.body.username
}, function(err, user) {
if (err) throw err;

if (!user) {
res.status(500).send('User not found');
} else {
// Check if password matches
user.comparePassword(req.body.password, function(err, isMatch) {
if (isMatch && !err) {
// Create token if the password matched and no error was thrown
var token = jwt.sign(user.toJSON(), config.secret, {
expiresIn: '7 days'
});
res.json({'access_token' : token});
} else {
res.status(500).send('Passwords did not match');
}
});
}
});
};

exports.register = function(req, res) {
if(!req.body.email || !req.body.password) {
res.status(500).send('Please enter email and password');
}
else {
const newUser = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password
});

// Attempt to save the user
newUser.save(function(err) {
if (err) {
res.status(500).send('That email address already exists');
} else {
res.json(jb.beautify('','Registration Successful'));
}
});
}
};

exports.dashboard = function(req, res) {
User.findOne({
_id: req.user._id
}, function(err, user) {
if (err) throw err;
res.json(jb.beautify({ user: user },'User retrieved successfully'));
});
};

exports.unauthorized = function(req, res) {
res.json('Unauthorised');
};

8. Update routes.js with the following code

'use strict';
var passport = require('passport');
var userController = require('../controllers/userController');

module.exports = function(apiRoutes) {

/* GET home page. */
apiRoutes.get('/', function(req, res, next) {
res.send('Express RESTful API with nodemon');
});

// Register new users
apiRoutes.post('/register', userController.register);

// Authenticate the user and get a JSON Web Token to include in the header of future requests.
apiRoutes.post('/login', userController.login);

apiRoutes.get('/unauthorized', userController.unauthorized);

// Protect dashboard route with JWT
apiRoutes.get('/dashboard', passport.authenticate('jwt', { session: false }), userController.dashboard);


};

9. To serve the project run npm run dev

**If you use postman as your api client for testing, here is the collection link : https://www.getpostman.com/collections/797dd4fa6cb53182b2b1

This brings us to the end of the Part 2 of the mean framework series.

Links to the rest of the parts will be added later along with a Github repository with the full framework. If you have missed the previous parts, you can check them out here: Part 1

Feel free to Comment, Share, Clap this post. Thanks for reading!

--

--