├── .gitignore ├── .DS_Store ├── public ├── .DS_Store ├── admin.png ├── allUsers.png ├── developer.png ├── admin-login.png ├── delete-access.png ├── unauthorized.png ├── developer-login.png ├── error-developer.png ├── users-developers.png └── delete-access-denied.png ├── routes ├── auth-routes.js └── api-routes.js ├── model ├── auth-model.js └── user-model.js ├── package.json ├── README.md ├── index.js └── controller └── controller.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/Secure-REST-API-Express-Node-MongoDB/master/.DS_Store -------------------------------------------------------------------------------- /public/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/Secure-REST-API-Express-Node-MongoDB/master/public/.DS_Store -------------------------------------------------------------------------------- /public/admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/Secure-REST-API-Express-Node-MongoDB/master/public/admin.png -------------------------------------------------------------------------------- /public/allUsers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/Secure-REST-API-Express-Node-MongoDB/master/public/allUsers.png -------------------------------------------------------------------------------- /public/developer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/Secure-REST-API-Express-Node-MongoDB/master/public/developer.png -------------------------------------------------------------------------------- /public/admin-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/Secure-REST-API-Express-Node-MongoDB/master/public/admin-login.png -------------------------------------------------------------------------------- /public/delete-access.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/Secure-REST-API-Express-Node-MongoDB/master/public/delete-access.png -------------------------------------------------------------------------------- /public/unauthorized.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/Secure-REST-API-Express-Node-MongoDB/master/public/unauthorized.png -------------------------------------------------------------------------------- /public/developer-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/Secure-REST-API-Express-Node-MongoDB/master/public/developer-login.png -------------------------------------------------------------------------------- /public/error-developer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/Secure-REST-API-Express-Node-MongoDB/master/public/error-developer.png -------------------------------------------------------------------------------- /public/users-developers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/Secure-REST-API-Express-Node-MongoDB/master/public/users-developers.png -------------------------------------------------------------------------------- /public/delete-access-denied.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chandu-muthyala/Secure-REST-API-Express-Node-MongoDB/master/public/delete-access-denied.png -------------------------------------------------------------------------------- /routes/auth-routes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const controller = require('../controller/controller'); 3 | const router = express.Router(); 4 | router.route('/signup').get(controller.authIndex) 5 | .post(controller.authSignup); 6 | router.route('/login').post(controller.login); 7 | 8 | module.exports = router; -------------------------------------------------------------------------------- /model/auth-model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const uniqueValidator = require('mongoose-unique-validator'); 3 | 4 | const authSchema = mongoose.Schema({ 5 | name: { type: String, required: true}, 6 | email: { type: String, required: true, unique:true}, 7 | password: { type: String, required: true}, 8 | role: { type: String, required: true}, 9 | }); 10 | authSchema.plugin(uniqueValidator); 11 | module.exports = mongoose.model('User', authSchema); -------------------------------------------------------------------------------- /model/user-model.js: -------------------------------------------------------------------------------- 1 | 2 | var mongoose = require('mongoose'); 3 | // Setup the schema 4 | var userSchema = mongoose.Schema({ 5 | name: { 6 | type: String, 7 | required: true 8 | }, 9 | email: { 10 | type: String, 11 | required: true, 12 | }, 13 | role: { 14 | type: String, 15 | required: true, 16 | }, 17 | create_date: { 18 | type: Date, 19 | default: Date.now 20 | } 21 | }); 22 | // Export User model 23 | var User = module.exports = mongoose.model('user', userSchema); 24 | module.exports.get = function (callback, limit) { 25 | User.find(callback).limit(limit); 26 | } -------------------------------------------------------------------------------- /routes/api-routes.js: -------------------------------------------------------------------------------- 1 | var router = require('express').Router(); 2 | var controller = require('../controller/controller.js'); 3 | router.get('/', function(req, res){ 4 | res.json({ 5 | status: 'API is Working', 6 | message: 'Node + Express + MongoDB: Nodemon Server', 7 | }); 8 | }); 9 | // users routes 10 | router.route('/users').get([controller.checkLogin, controller.index]) 11 | .post([controller.checkLogin, controller.newUser]); 12 | 13 | router.route('/user/:id').get(controller.view) 14 | .put([controller.checkLogin, controller.checkRole, controller.update]) 15 | .delete([controller.checkLogin, controller.checkRole, controller.delete]); 16 | // Expose API routes to public 17 | module.exports = router; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "secure-rest-api-express-node", 3 | "version": "1.0.0", 4 | "description": "A simple secure node application using JWT", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/cmuth001/Secure-REST-API-NodeJS.git" 12 | }, 13 | "author": "chandrasekhar reddy muthyala", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/cmuth001/Secure-REST-API-NodeJS/issues" 17 | }, 18 | "homepage": "https://github.com/cmuth001/Secure-REST-API-NodeJS#readme", 19 | "dependencies": { 20 | "bcrypt": "^3.0.6", 21 | "body-parser": "^1.19.0", 22 | "express": "^4.17.1", 23 | "jsonwebtoken": "^8.5.1", 24 | "mongodb": "^2.2.33", 25 | "mongoose": "^5.6.5", 26 | "mongoose-unique-validator": "^2.0.3" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Secure-REST-API-NodeJS 2 | 3 | ## Signup 4 | | ![Admin Signup](public/admin.png) | ![Developer Signup](public/developer.png) | 5 | |:---:|:---:| 6 | | Admin Signup | Developer Signup | 7 | 8 | ## Login 9 | 10 | ### Admin Login 11 | 12 | | ![Admin Login](public/admin-login.png) | 13 | |:---:| 14 | | Admin Login | 15 | 16 | Admin have access to get all the users(admin/developers) in the database. 17 | 18 | | ![All Users](public/allUsers.png) | 19 | |:---:| 20 | | All Users | 21 | 22 | Admin role have access to delete the users in the table 23 | 24 | | ![Delete User](public/delete-access.png) | 25 | |:---:| 26 | | Access to delete user | 27 | 28 | ### Developer Login 29 | 30 | | ![Developer Login](public/developer-login.png) | 31 | |:---:| 32 | | Developer Login | 33 | 34 | Developer can get all the users with role developer 35 | 36 | | ![Developer Users](public/users-developers.png) | 37 | |:---:| 38 | | Developer Users | 39 | 40 | Developer does not have access to delete user 41 | 42 | | ![Access Denied](public/delete-access-denied.png) | 43 | |:---:| 44 | | Access Denied | 45 | 46 | 47 | I hope this tutorial helped you in creating a simple **Secure REST API using NodeJs and Mongodb**. To Know more about how to create a simple REST API click [here](https://github.com/cmuth001/REST-API-Express-Node-MongoDB). 48 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Importing Express Framework 2 | var express = require("express"); 3 | 4 | var bodyParser = require('body-parser'); 5 | // Import Mongoose 6 | let mongoose = require('mongoose'); 7 | // Intializing the app 8 | var app = express(); 9 | 10 | // Import Route Module 11 | var apiRoutes = require('./routes/api-routes'); 12 | var authRoutes = require('./routes/auth-routes'); 13 | // Configure bodyparser to handle post requests 14 | app.use(bodyParser.urlencoded({ 15 | extended: true 16 | })); 17 | app.use(bodyParser.json()); 18 | // Setup server port 19 | var port = process.env.PORT || 3000; 20 | app.use('/v1/api', apiRoutes); 21 | app.use('/v1/auth', authRoutes); 22 | 23 | mongoose 24 | .connect( 25 | "mongodb+srv://cmuth001:uIQc0vhkYeHTbzkI@chat-room-eqvp3.mongodb.net/secure-rest-api", { useNewUrlParser: true } 26 | ) 27 | .then(() => { 28 | console.log("Connected to database!"); 29 | }) 30 | .catch(() => { 31 | console.log("Connection failed!"); 32 | }); 33 | app.get('/', function (req, res) { 34 | res.json({ 35 | status: 'Main page', 36 | message: 'Welcome to the world of RESTAPI', 37 | description: 'Goto /api to explore API' 38 | }); 39 | }); 40 | // Launch app to listen to the specified PORT 41 | app.listen(3000, () => { 42 | console.log(`Server running on port ${port}`); 43 | }); 44 | 45 | -------------------------------------------------------------------------------- /controller/controller.js: -------------------------------------------------------------------------------- 1 | var User = require('../model/user-model.js'); 2 | const Auth = require('../model/auth-model.js'); 3 | const bcrypt = require('bcrypt'); 4 | const jwt = require('jsonwebtoken'); 5 | const private_Key = 'this is my secret key'; 6 | var login_role = ''; 7 | exports.authIndex = (req, res, next) => { 8 | res.status(200).json({ 9 | message: 'Auth Index Route Working', 10 | }); 11 | }; 12 | exports.checkLogin = (req, res, next) => { 13 | 14 | if (req.headers['authorization']) { 15 | 16 | try { 17 | let authorization = req.headers['authorization'].split(' '); 18 | if (authorization[0] !== 'Bearer') { 19 | return res.status(401).json({ 20 | Error: 'Invalid syntax of token', 21 | status: 401, 22 | }); 23 | } else { 24 | // console.log("validJWTNeeded: ", req.headers['authorization']); 25 | req.jwt = jwt.verify(authorization[1], private_Key); 26 | 27 | return next(); 28 | } 29 | } catch (err) { 30 | return res.status(403).json({ 31 | message: 'Erorr occured during authentication', 32 | Error: err, 33 | status: 403, 34 | }); 35 | } 36 | } else { 37 | return res.status(401).json({ 38 | Error: 'Token is required!', 39 | status: 401, 40 | }); 41 | } 42 | }; 43 | exports.checkRole = (req, res, next) => { 44 | 45 | if(login_role == 'admin'){ 46 | console.log("User have Access"); 47 | return next(); 48 | }else{ 49 | console.log("Access denied!"); 50 | return res.status(401).json({ 51 | message: 'Access denied!' 52 | }); 53 | } 54 | } 55 | exports.login = (req, res, next) => { 56 | // console.log(req.headers) 57 | // console.log("---") 58 | Auth.findOne({email: req.body.email}) 59 | .then( user => { 60 | if(!user){ 61 | return res.status(401).json({ 62 | message: 'User does not exist!' 63 | }); 64 | } 65 | // console.log("login: ", user) 66 | bcrypt.compare(req.body.password, user.password) 67 | .then(result => { 68 | if(!result){ 69 | return res.status(401).json({ 70 | message: 'Autentication Failed!', 71 | status: result, 72 | }); 73 | } 74 | else{ 75 | login_role = user.role; 76 | const token = jwt.sign( 77 | {email: user.emit, user_id: user._id}, 78 | private_Key, 79 | {expiresIn:'1h'} ); 80 | 81 | return res.status(401).json({ 82 | message: 'Autenticated successfully!', 83 | token: token, 84 | }); 85 | } 86 | 87 | }) 88 | .catch( err => { 89 | return res.status(401).json({ 90 | message: 'Error occured in authentication!', 91 | error: err, 92 | }); 93 | }); 94 | 95 | }); 96 | 97 | } 98 | exports.authSignup = (req, res, next) => { 99 | bcrypt.hash(req.body.password, 10) 100 | .then( hash => { 101 | const authDetails = new Auth({ 102 | email: req.body.email, 103 | password: hash, 104 | name: req.body.name, 105 | role: req.body.role, 106 | }); 107 | authDetails.save() 108 | .then(result => { 109 | res.status(201).json({ 110 | message: 'New user is registered', 111 | result: result, 112 | }); 113 | }) 114 | .catch( err => { 115 | res.status(501).json({ 116 | message: 'user already exists', 117 | error: err, 118 | }); 119 | }); 120 | }); 121 | }; 122 | exports.index = (req, res, next) => { 123 | User.get((err, users) => { 124 | var slice_deatils = []; 125 | users.forEach(function(item) { 126 | // console.log(item); 127 | if(login_role == item.role || login_role == 'admin'){ 128 | slice_deatils.push( 129 | { id: item._id, 130 | name: item.email, 131 | role: item.role, 132 | create_date:item.create_date, 133 | }); 134 | } 135 | 136 | }); 137 | 138 | if(err){ 139 | res.json({ 140 | status: "Error occured in getting users", 141 | message: err, 142 | }); 143 | } 144 | res.json({ 145 | status: 200, 146 | message: "users retrieved successfully", 147 | data: slice_deatils, 148 | }); 149 | }); 150 | }; 151 | 152 | exports.newUser = (req, res) => { 153 | var user = new User(); 154 | console.log(req.body); 155 | user.name = req.body.name ? req.body.name : user.name; 156 | user.email = req.body.email ? req.body.email : user.email; 157 | user.role = req.body.email ? req.body.email : user.email; 158 | 159 | user.save((err) => { 160 | if(err){ 161 | return res.json({ 162 | status: 'Error in inserting', 163 | message: err, 164 | }); 165 | } 166 | res.json({ 167 | status: 'New User inserted successfully!', 168 | message: user, 169 | }); 170 | }); 171 | }; 172 | 173 | exports.view = (req, res) => { 174 | // console.log(req.params.id); 175 | var id = req.params.id; 176 | 177 | User.findById(id, (err, user)=>{ 178 | if(err){ 179 | return res.json({ 180 | status: "Error In fetching user", 181 | message: err, 182 | }); 183 | } 184 | res.json({ 185 | status: 'User Found in the DB!', 186 | message: user 187 | }); 188 | }); 189 | }; 190 | 191 | exports.update = (req, res) => { 192 | var id = req.params.id; 193 | User.findById(id, (err, user) => { 194 | 195 | if(err){ 196 | return res.json({ 197 | status: 'Error in finding user id', 198 | message: err, 199 | }); 200 | } 201 | user.name = req.body.name?req.body.name:user.name; 202 | user.email = req.body.email?req.body.email: user.email 203 | user.save((err)=>{ 204 | if(err){ 205 | return res.json({ 206 | status: 'Error in updating user details', 207 | message: userrer, 208 | }); 209 | } 210 | res.json({ 211 | status: 'User details successfully updated', 212 | message: user, 213 | }); 214 | }); 215 | 216 | }); 217 | }; 218 | 219 | exports.delete = (req, res) => { 220 | var id = req.params.id; 221 | User.findById(id, (err, user)=>{ 222 | if(err){ 223 | return res.json({ 224 | status: 'Error in finding user to delete', 225 | message: err, 226 | }); 227 | } 228 | user.delete((err)=>{ 229 | if(err){ 230 | return res.json({ 231 | status: 'Error in deleting user', 232 | message: err, 233 | }); 234 | } 235 | res.json({ 236 | status: 'Successfully deleted', 237 | message: user 238 | }); 239 | }); 240 | }); 241 | }; --------------------------------------------------------------------------------