NodeJS JWT authentication MongoDB

NodeJS JWT authentication MongoDB

In this article, we will implement nodejs JWT authentication MongoDB. This article requires you to have basic knowledge of nodejs. Authentication can be complex but I will make it as simple as possible.

Installation requirement

express: Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. 
mongoose:Mongoose provides a straight-forward, schema-based solution to model your application data. It includes built-in type casting, validation, query building, business logic hooks and more, out of the box.
jsonwebtoken: JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
cors: Cross-origin resource sharing (CORS) is HTTP-based, which allows the server to specify a source (domain, scheme, or port) other than the source (domain, scheme, or port) from which the browser needs to load the resource. It’s a mechanism.
cryptr: cryptr is a simple aes-256-gcm encrypt and decrypt module for node.js

Installation

You should already have your project ready, if not you can run the command below to create a project quickly

/* skip this if you already have a project */npm install -g express-generator

The next command will install the required npm libraries

npm install cors cryptr jsonwebtoken mongoose

Thereafter your package.json file should look like what we have below

/* package.json file*/
{
  "name": "sample_app",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": " node app.js",
    "nodemon": "nodemon app.js"
  },
  "keywords": [],
  "author": "simon jerry",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5",
    "cryptr": "^4.0.2",
    "express": "^4.17.1",
    "jsonwebtoken": "^8.5.1",
    "mongoose": "^5.7.4",
    "nodemon": "^1.19.4"
  },
  "devDependencies": {}
}

NB: I added nodemon for easy application startup if any change is made.

Folder structure below

node_authentication/
├── config
├── controllers
├── models
├── node_modules
├── public
└── routes

Next, we will write our server in the app.js file

/* Your code... */



const cors = require('cors'); 
const routeController = require('./routes/route-controller'); // import router controller file right after this file.
 var express = require('express');
 var app = express();

 app.use(express.static('public'));

 app.use(express.json()); 

 app.use(cors());

const port = process.env.PORT || "5000"; 
// routes
app.use("/api", routeController );

app.listen(port, () => {
  console.log(`nodejs server Listening to requests on http://localhost:${port}`);
});

Next, create your endpoint in the router controller file.

/* route-controller.js file */      
const express = require('express');
const router = express.Router();

router.post('/login', userController.login);  // login route and controller handler
router.post('/sign-up', userController.createUser); //sign up route and controller handler
router.get('/get-user-details', userController.getUserDetails);
router.put('/update-user-details', userController.updateUserDetails);
router.get('/get-my-profile', userController.getMyProfile);

module.exports = router;

Next is the mongoose schema in the user model file.

/* Your code.. */
const mongoose = require('mongoose'); mongoose importation for generating schema
const jwt = require('jsonwebtoken');   //jwt immportation
const APP_SECRET = 'myapp_secret002';

var userSchema = mongoose.Schema({

    email: {
        type: String, required: true, unique: true,
    },
    firstName: {
        type: String,
    },
    lastName: {
        type: String,
    },
    password: {
        type: String,  required:'password is required',  minlength : [6, 'password must be at least 6 character']
    } ,
    date: {
        type: Date, default: Date.now()
    },
});


// a custom schema method for generating jwt token ,you can read about shema methods here.
// this method uses JWT to sign user's credentials 
userSchema.methods.generateJwt = (user)=> {
    var expiry = new Date();
    expiry.setDate(expiry.getDate() + 1);
    return jwt.sign({_id: user._id, email: user.email,
        exp: parseInt(expiry.getTime() / 1000),},
         APP_SECRET);
}

// this schema is model as USER or USERS  in the database
mongoose.model('User', userSchema);

next is the Jwt helper method that will verify tokens for authenticated users.

/* Your code... */
const jwt = require('jsonwebtoken');
const APP_SECRET = 'my_app_secret002';

const verifyJwtToken = (req, res, next)=> {
    var token;
    if('authorization' in req.headers)
    token = req.headers['authorization'].split(' ')[1];  //splt incoming request and get the token

    if(!token){
        return res.status(403).send(({auth: false, message: 'no token provided.'}));
    }else{
        jwt.verify(token, APP_SECRET, (error, decoded)=> {     //verify token with  signing signature
            if(error)
            return res.status(401).send({auth: false, message:'token authentication failed.'});
            else{
                req._id = decoded._id;    // the current user id is attached to the header
                next();   // user passed authentication process
            }
        });
    }
}
module.exports = {verifyJwtToken}

Next, is the MongoDB database connection

/* Your code... */ 
 const mongoose = require('mongoose');
const DATABASE = 'mongodb://localhost:27017/sample';  // database name [sample]
mongoose.connect(DATABASE,{useNewUrlParser : true, useUnifiedTopology: true},(err) => {
    if(!err) console.log(DATABASE,'mongodb connection successful..');
    else
    console.log("error in connection"+ JSON.stringify(err, undefined, 2));
});  
   
require('./users_model');   // user schema is registered

Next, we will need to start the database as soon as the server is started, this will be done by updating the APP.JS file with the DB connection file path. We will do the same with the JWT helper.

/* Your code... */
require('./config/jwt_helper');
require('./models/db');

o it looks like this:

/* Your code... */

require('./config/jwt_helper');
require('./models/db');

const cors = require('cors');
const routeController = require('./routes/route-controller');
 var express = require('express');
 var app = express();

 app.use(express.static('public'));
 app.use(express.json()); 
 app.use(cors());
const port = process.env.PORT || "5000"; 
// routes
app.use("/api", routeController );

app.listen(port, () => {
  console.log(`nodejs server Listening to requests on http://localhost:${port}`);
});

We also need to update the router controller file. We need to secure the protected endpoint for logged-in users.

/* Your code... */
 const express = require('express');
const router = express.Router();
const userController = require('../controllers/user_controller');
const jwt_helper = require('../config/jwt_helper');

router.post('/login', userController.login);
router.post('/sign-up', userController.createUser);
router.get('/get-user-details', jwt_helper.verifyJwtToken, userController.getUserDetails);   //protected end point
router.put('/update-user-details', jwt_helper.verifyJwtToken, userController.updateUserDetails);  // protected end point
router.get('/get-my-profile', jwt_helper.verifyJwtToken, userController.getMyProfile);  // protected wnd point


module.exports = router; 

Next, start up using npm start or node app.js or just nodemon. You should get a message like the one below.

/* console... */
[nodemon] starting `node app.js`
(node:12244) Warning: Accessing non-existent property 'count' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
(node:12244) Warning: Accessing non-existent property 'findOne' of module exports inside circular dependency
(node:12244) Warning: Accessing non-existent property 'remove' of module exports inside circular dependency
(node:12244) Warning: Accessing non-existent property 'updateOne' of module exports inside circular dependency
nodejs app server Listening to requests on http://localhost:5000
(node:12244) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.
mongodb://localhost:27017/sample mongodb connection successful..

We have gotten out server running, next we will create a user record from the postman.

Node js  registration example

Below is a screenshot of successful registration.

nodejs create user

Not the response and status code of (200) ok. Below is the newly registered user in our database.

We will do another register for confirmation purposes.

We now have two records on our database, let us try to access the protected endpoints from postman.

/* protected end point */
router.get('/get-user-details', jwt_helper.verifyJwtToken, userController.getUserDetails)

We get the error message no token provided

/* 403 forbidden*/ { "auth": false, "message": "no token provided." }

next we will perform a login, add the token to the header and access the protected endpoint

The screenshot below shows login was successful. note the JWT response and status code 200.

node.js express login example

Next, we will add this token to the header and access the protected endpoint. Adding token to the header should take the format below.

/* header */header : {authorization : 'bearer token}

Note how the token was added to the header following the given format above. The server grants access to the protected route and return the user details of the logged-in User.

/* server response */ { "user": { "date": "2021-10-05T08:31:06.105Z", "_id": "615c0fde4561152fd4098c7f", "firstName": "simon", "lastName": "jerry", "email": "person@mail.com", "password": "c1288b6aed4d16e07457ab6e95907af742148a9ff8c3c372", "__v": 0 } }

This sample project is on Github, you can explore the code here.

II also urge you to look into nodejs best practice here.

If you find this helpful, comment and share with a friend, this keeps me motivated and cut out time from my busy schedule to drop more post like this.

Thanks

14 thoughts on “NodeJS JWT authentication MongoDB

  1. Hi, Neat post. There’s a problem with your website in internet explorer, would check this?IE still is the market leader and a big portion of people will miss your great writing due to this problem.

  2. You actually make it seem so easy together with your presentation but I in finding this matter to be actually one thing which I feel I would by no means understand. It kind of feels too complex and very large for me. I’m taking a look ahead on your next submit, I will attempt to get the hang of it!

  3. I’m still learning from you, but I’m making my way to the top as well. I absolutely enjoy reading everything that is posted on your site.Keep the information coming. I liked it!

  4. I am not sure the place you are getting your information, however great topic. I must spend a while learning more or figuring out more. Thanks for fantastic information I was in search of this information for my mission.

  5. I’m truly enjoying the design and layout of your blog. It’s a very easy on the eyes which makes it much more pleasant for me to come here and visit more often. Did you hire out a designer to create your theme? Excellent work!

  6. I discovered your weblog website on google and test just a few of your early posts. Continue to keep up the excellent operate. I just further up your RSS feed to my MSN Information Reader. Seeking ahead to studying extra from you in a while!?

  7. I have acquired some new things from your web site about computer systems. Another thing I have always considered is that computers have become something that each family must have for most reasons. They provide convenient ways in which to organize the home, pay bills, shop, study, focus on music and even watch television shows. An innovative strategy to complete these types of tasks is with a laptop. These desktops are mobile, small, effective and mobile.

  8. You can certainly see your enthusiasm in the work you write. The world hopes for more passionate writers like you who are not afraid to say how they believe. Always go after your heart.

Leave a Reply

Your email address will not be published. Required fields are marked *