How To Manage User Roles In NodeJS

How To Manage User Roles In Node.js ? This kind of a hard things right?. No. This is very easy. Try to understand this article I am 100% sure you can handle this. User permission systems are the core of nearly every application. In this video I will be showing you, how to set up a flexible and simple user permission system which you can use in any Node.js application. Update your node JS latest version and Let’s see how to handle user Authentication in Node.js.

So, In here, I am using Node.js. You have to configure your project environment (Creating a Package.json file) using “npm init“. Then install “nodemon“. Click here to refer “Nodemon”. After that install express using “npm i express

npm i nodemon

Then create a folder called “data”. I am going to use dummy data in here.

Inside the data folder, create a js file called. “user.data”. The file name and the extension should be “user.data.js”. After that create your own data like this. you can use your own data.

const ROLE = {
    ADMIN: 'admin',
    USER: 'user'
}

module.exports = {
    ROLE: ROLE,
    users: [
        { id: 1, name: 'Osanda', role: ROLE.ADMIN },
        { id: 2, name: 'Billy', role: ROLE.USER },
        { id: 3, name: 'John', role: ROLE.USER }
    ],
    projects: [
        { id: 1, name: "Osanda's Project", userId: 1 },
        { id: 2, name: "Billy's Project", userId: 2 },
        { id: 3, name: "John's Project", userId: 3 }
    ]
}

In here, I am going to develop user access to each project. So that is why I create a array called “projects” in user.data.js file.

Let’s get into development. Create a server.js file. (App..js root file)

Then import express and the server.js code look like this.

const express = require('express')
const app = express()
const { users } = require('./data/user.data')

app.use(express.json())
app.use(setUser)

app.get('/', (req, res) => {
  res.send('Home Page')
})

app.get('/userDashboard', (req, res) => {
  res.send('User Dashboard Page')
})

app.get('/adminDashboard', (req, res) => {
  res.send('Admin Dashboard Page')
})

function setUser(req, res, next) {
  const userId = req.body.userId
  if (userId) {
    req.user = users.find(user => user.id === userId)
  }
  next()
}

app.listen(5000, () => {
    console.log("Server is up and running on port number : 5000");
});

I am going to develop this Node API to access user Dashboard for users and Admin Dashboard for admins. So I created get methods to define routes. You can use your own route.js file and the controller file. In here I just creating a simple API to understand “How To Manage User Roles In NodeJS”.

Install REST CLIENT extension in VSCode

First let’s check this routes. I am going to use “REST CLIENT” extension in VSCode. Install this extension that will help you to get response without using postman.

REST CLIENT is an extension to run your endpoints. Also you can use Postman. ( You can download by clicking here. ). After installing REST CLIENT, you can create a file in the root folder. I am going to call this as “run.rest”

Copy this code and paste it in the run.rest file. Before send the request. Run your API using nodemon server.js.

Then send your request. you can a response like this.

Try to send these requests also.

http://localhost:5000/userDashboard
http://localhost:5000/adminDashboard

Authentication file – How To Manage User Roles In NodeJS

Okay’ let’s create the Authentication. I am going to create a file called “Authentication.js” in my root folder. Inside the file paste this code.

function authUser(req, res, next) {
    if (req.user == null) {
        res.status(403)
        return res.send('You need to sign in')
    }

    next()
}

module.exports = {
    authUser
}

Then declare on server.js file like this.

const { authUser} = require('./Authentication')

Then modify your get methods like this.

app.get('/userDashboard', authUser,  (req, res) => {
  res.send('User Dashboard Page')
})

app.get('/adminDashboard', authUser ,  (req, res) => {
  res.send('Admin Dashboard Page')
})

After that try to send request again. you will see a message as “you need to sign in”. like this.

Try to send request like this.

GET http://localhost:5000/adminDashboard
Content-Type: application/json

{
    "userId": 1
}

As you can see the route works.

Handle Roles in node JS tutorials

Go to your Authentication file and paste this function also.

function authRole(role) {
    return (req, res, next) => {
        if (req.user.role !== role) {
            res.status(401)
            return res.send('Not allowed')
        }

        next()
    }
}

and define this function in the module.exports like this.

module.exports = {
    authUser,
    authRole
}

The go to your server.js file and defin auth role also. like this.

const { authUser, authRole } = require('./Authentication')

After that replace with this with your user.data.js file import.

const { ROLE, users } = require('./data/user.data')

I am going to add this function to my admin route. like this.

app.get('/adminDashboard', authUser , authRole(ROLE.ADMIN),  (req, res) => {
  res.send('Admin Dashboard Page')
})

the final server.js file look like this. Try to refer and fill your missing codes.

const express = require('express')
const app = express()
const { ROLE, users } = require('./data/user.data')
const { authUser, authRole } = require('./Authentication')

app.use(express.json())
app.use(setUser)

app.get('/', (req, res) => {
  res.send('Home Page')
})

app.get('/userDashboard', authUser,  (req, res) => {
  res.send('User Dashboard Page')
})

app.get('/adminDashboard', authUser , authRole(ROLE.ADMIN),  (req, res) => {
  res.send('Admin Dashboard Page')
})

function setUser(req, res, next) {
  const userId = req.body.userId
  if (userId) {
    req.user = users.find(user => user.id === userId)
  }
  next()
}

app.listen(5000, () => {
    console.log("Server is up and running on port number : 5000");
});

After that try send a request by using this route. use your user as non admin. If you use admin you can go to the Admin dashboard page.

GET http://localhost:5000/adminDashboard
Content-Type: application/json

{
    "userId": 2
}

you can see a message as “Not allowed”. Because we develop this route to access only for admins. That is why I told you to use a ID as admin to get an access to admin route. If you use other user IDs like non admin user IDs, you can’t access to admin routes. Now you can see the user permissions are working fine. you can develop your own user roles and try to make each route for each role.

Project for each route and for the user in node JS tutorial – How To Manage User Roles In NodeJS Part 02

I am going to define specific route for specific roles. In your data.js file, you can an array called project. I am going to use this array to specify each project for each role. First of all wee need a file to control. I am going to create a new file called “projectPermission.js” in my root folder. If you want the best practices, you create your won routes and controllers files. In here I am creating a simple file to understand “How to handle user authentication in Node.js tutorials”.

In my projectPermission.js file, I am going to write this code. copy and paste into your code.

const express = require('express')
const router = express.Router()
const { projects } = require('./data/user.data')

router.get('/', (req, res) => {
  res.json(projects)
})

router.get('/:projectId', setProject, (req, res) => {
  res.json(req.project)
})

function setProject(req, res, next) {
  const projectId = parseInt(req.params.projectId)
  req.project = projects.find(project => project.id === projectId)
  
  if (req.project == null) {
    res.status(404)
    return res.send('Project not found')
  }
  next()
}

module.exports = router

After that create another file to manage permissions. I am going to create as “permissionController.js”. In here we calling roles in our data.js file and check the authentication. Try to refer the bellow code and try to understand how I use this code. This is the permissionController.js code.

const { ROLE } = require('./data/user.data')

function canViewProject(user, project) {
  return (
    user.role === ROLE.ADMIN ||
    project.userId === user.id
  )
}

function scopedProjects(user, projects) {
  if (user.role === ROLE.ADMIN) return projects
  return projects.filter(project => project.userId === user.id)
}

function canDeleteProject(user, project) {
  return project.userId === user.id
}

module.exports = {
  canViewProject,
  scopedProjects,
  canDeleteProject
}

There are 3 functions. Lets discuss only canViewProject function for now. In this function we want to check if this user is an admin, because if that’s true they can access every project. Or if the user is actually part of that project, for an example in our data.js file you can see each user is a part of a project. Then they also has the access.So what we can do is we can assign project.userID to user.user.id. So that is why we called as user.role === ROLE.ADMIN OR project.userId === user.id. so either the user is an admin or they created the project themselves then this function will return true.

So in our projectPermission.js file, we need to set the authentication around that. The first thing that I want to do is authenticate that the user actually exists. We need to assign “authUser” function in our authentication file.

Create projectPermission.js file to manage user roles for each project

In your projectPermission file, replace this code with the existing one. and make sure to define authUse from the authentication file.

const { authUser } = require('./Authentication')
router.get('/:projectId', setProject, authUser, authGetProject, (req, res) => {
  res.json(req.project)
})

We need to create this “authGetProject” function in this file. First of all define “canViewProject” function from the permisionController file.

const { canViewProject, canDeleteProject, scopedProjects } = require('./permissionController')

For the easiest way open you projectPermission.js file and paste the below code into yours.

const express = require('express')
const router = express.Router()
const { projects } = require('./data/user.data')
const { authUser } = require('./Authentication')
const { canViewProject, canDeleteProject, scopedProjects } = require('./permissionController')

router.get('/', authUser, (req, res) => {
  res.json(scopedProjects(req.user, projects))
})

router.get('/:projectId', setProject, authUser, authGetProject, (req, res) => {
  res.json(req.project)
})

router.delete('/:projectId', setProject, authUser, authDeleteProject, (req, res) => {
  res.send('Deleted Project')
})

function setProject(req, res, next) {
  const projectId = parseInt(req.params.projectId)
  req.project = projects.find(project => project.id === projectId)
  
  if (req.project == null) {
    res.status(404)
    return res.send('Project not found')
  }
  next()
}

function authGetProject(req, res, next) {
  if (!canViewProject(req.user, req.project)) {
    res.status(401)
    return res.send('Not Allowed')
  }

  next()
}

function authDeleteProject(req, res, next) {
  if (!canDeleteProject(req.user, req.project)) {
    res.status(401)
    return res.send('Not Allowed')
  }

  next()
}

module.exports = router

“authDeleteProject” will be discuss later. First we discuss “authGetProject” function. In this function looks the request user data is a user and send the response.

Before Run this, we have to define projectPermission routes in our server.js file. Define it like this.

const projectPermission = require('./projectPermission')


app.use('/projects', projectPermission)

Then go to your run.rest file and try to pass some values with the below endpoint.

GET http://localhost:5000/projects/1
Content-Type: application/json

{
    "userId": 1
}

In my data set user ID = 1 is a admin user and ID number 2 and 3 are non admins. If I try to pass userID as 1 with project id as number 1, you can see a response like this.

If I try to pass userID as number 2 and project id as number 1, the response will be “not allowed”. It means user id number 2 is a non admin and that user can’t access to the admin project. Because project number 1 is an admin project. That’s because “scopedProjects” function that we assign in the permissionController.js file.

If I try to pass the user id as number 1 and project id as number 2 or 3, the Response will show the project data. Because we define canViewProject, admin can access every single project. But the non admins can’t access the all project and only they can access their projects.

If I pass user id as number 1 and route like “http://localhost:5000/projects”, all projects data will display as a response.

Deleting a Project with user permissions

router.delete('/:projectId', setProject, authUser, authDeleteProject, (req, res) => {
  res.send('Deleted Project')
})

You can see a route like this in your “projectPermission.js” file. And also the below method.

function authDeleteProject(req, res, next) {
  if (!canDeleteProject(req.user, req.project)) {
    res.status(401)
    return res.send('Not Allowed')
  }

  next()
}

And check out your permissionController.js file to have this below code also.

function canDeleteProject(user, project) {
  return project.userId === user.id
}

Please make sure to define in the module.exports like this.

module.exports = {
  canViewProject,
  scopedProjects,
  canDeleteProject
}

Then try to send a request like this and you will get a response like this also. Make sure to change the request as “DELETE”.

That’s it. you can get the code in https://github.com/ozandabb/How-To-Manage-User-Roles-In-NodeJS.

Thank you

More Articles from my blog