Header Ads

Securing Node.js APIs with JWT & Role-Based Authentication

 Learn how to secure Node.js APIs using JWT and role-based authorization. Protect routes, verify tokens, and manage user access effectively.

When building APIs for modern applications, especially those consumed by mobile or frontend frameworks like Ionic, ensuring secure access is critical. One of the most efficient ways to do this is by using JSON Web Tokens (JWT) along with role-based authorization.

In this guide, we’ll walk through how to:

  • Authenticate users using JWT
  • Protect API routes
  • Control access based on user roles



Why Use JWT for Authentication?

JWT is a compact, self-contained way to securely transmit information between two parties. It’s widely used for stateless authentication in RESTful APIs. After a successful login, the server generates a signed token containing user details. This token is returned to the client and must be included with every future request to confirm the user's identity and permissions


Benefits of JWT:

  • No session storage on the server
  • Works well with mobile and SPA (single-page applications)
  • Easily scalable and secure when implemented correctly



Setting Up the Project

First, let's create a basic Express API.

npm install express jsonwebtoken bcryptjs dotenv


Creating a Login Route

We’ll simulate a simple login system using hardcoded users for demonstration.

const express = require('express');

const jwt = require('jsonwebtoken');

const bcrypt = require('bcryptjs');

require('dotenv').config();


const app = express();

app.use(express.json());


// Simulated user database

const users = [

  { id: 1, username: 'admin', password: bcrypt.hashSync('admin123', 8), role: 'admin' },

  { id: 2, username: 'user', password: bcrypt.hashSync('user123', 8), role: 'user' }

];


// Login route

app.post('/login', (req, res) => {

  const { username, password } = req.body;

  const user = users.find((userEntry) => userEntry.username === username);

  

  if (!user || !bcrypt.compareSync(password, user.password)) {

    return res.status(401).json({ message: 'Invalid user credentials' });

  }


  const token = jwt.sign(

    { userId: user.id, role: user.role },

    process.env.JWT_SECRET,

    { expiresIn: '1h' }

  );


  res.json({ token });

});


Middleware to Verify JWT

Create a middleware function to validate incoming tokens.

function authenticateToken(req, res, next) {

  const authHeader = req.headers['authorization'];

  const token = authHeader?.split(' ')[1];


  if (!token) return res.status(401).json({ message: 'Token required' });


  jwt.verify(token, process.env.JWT_SECRET, (err, user) => {

    if (err) return res.status(403).json({ message: 'user Token is invalid' });

    req.user = user;

    next();

  });

}


Role-Based Access Control (RBAC)

Now, let's create middleware that allows access only to specific user roles.

function authorizeRoles(...allowedRoles) {

  return (req, res, next) => {

    if (!allowedRoles.includes(req.user.role)) {

      return res.status(403).json({ message: 'user access denied: Insufficient permissions' });

    }

    next();

  };

}


Protecting Routes

Use the middlewares on your API endpoints.

// Only accessible by admin

app.get('/admin', authenticateToken, authorizeRoles('admin'), (req, res) => {

  res.send('Welcome, Admin!');

});


// Accessible by both admin and user

app.get('/dashboard', authenticateToken, authorizeRoles('admin', 'user'), (req, res) => {

  res.send('Dashboard Access');

});


Testing the API

  1. Make a POST request  /login with username and password.

  2. Copy the token returned.

  3. Make a GET request to /admin or /dashboard With the token in the Authorization header:

Authorization: Bearer <token>


Summary

By using JWT-based authentication along with role-based authorization, your Node.js API becomes secure, scalable, and ready for production.

This pattern works seamlessly with mobile or web frontends, including hybrid apps built using Ionic + Angular or React

Post a Comment

0 Comments