Securing Nodejs(Express) REST API with Role-based access control(RBAC) using Keycloak

Saurav Samantray
5 min readMay 29, 2024


REST API could contain sensitive data(user information, financial details, or proprietary business data) and needs to be protected from unauthorized access. In this article, we will explore steps to secure a Nodejs(Express) REST API using RBAC(Role-based access control) setup in Keycloak.


Spin up Keycloak server — If you have Docker setup in your local system, you can use one of the existing GitHub repositories I created to spin up the Keycloak server —

Setup Keycloak

Step1: Access the Local Keycloak Server

Access the local Keycloak server setup in the previous setup at http://localhost:8080

Step2: Create a new client

Step3: Create Realm Roles

  • Navigate to the Realm roles in the left navigation menu and click on Create role
  • Create user role — express-user
  • Repeat the steps to create an admin role — express-admin

Step4: Create Users

Navigate to the Users section from the left navigation menu. Fill out the new user form and click on Create.

  • Navigate to the details of the newly created user —, go to the Credentials tab and Click on Set Password
  • Fill out the Set password form with the appropriate password. Make sure to mark the Temporary toggle button Off
  • Create another user

Step5: Assign roles to users

Navigate to the Role Mapping Tab on the user details page and click on the Assign Role button

  • Select express-user and click on the Assign button
  • Similarly, assign the express-admin role to user

Basic Express JS application to serve REST endpoints

Initialize a Node JS application

run the below set of commands to initialize a NodeJS application as our express server will reside inside the Node application.

mkdir secure-express-service
cd secure-express-service
npm init

The npm init command will initiate a series of prompts to create the base package.json. Sample input below

package name: (secure-express-service)
version: (1.0.0)
description: Express JS based REST APIs secured using Keycloak auth server
entry point: (index.js) app.js
test command:
git repository:
author: Saurav Samantray
license: (ISC)

Install dependencies

npm install express express-session keycloak-connect nodemon

Define main execution file — app.js

Add a file named app.js at the root level of your secure-express-service project.

Define imports and express app

// file - app.js

const express = require('express');
const session = require("express-session");
const Keycloak = require("keycloak-connect");

const app = express();
const PORT = 3000;


Setup Keycloak Middleware

// file - app.js


const USER_ROLE = process.env.USER_ROLE || 'express-user';
const ADMIN_ROLE = process.env.ADMIN_ROLE || 'express-admin';

const kcConfig = {
clientId: process.env.AUTH_CLIENT_ID || 'secure-express-service',
bearerOnly: true,
serverUrl: process.env.AUTH_SERVER || 'http://localhost:8080',
realm: process.env.AUTH_REALM || 'master'

const memoryStore = new session.MemoryStore();

Keycloak.prototype.accessDenied = function (request, response) {
response.setHeader('Content-Type', 'application/json')
response.end(JSON.stringify({ status: 401, message: 'Unauthorized/Forbidden', result: { errorCode: 'ERR-401', errorMessage: 'Unauthorized/Forbidden' } }))

const keycloak = new Keycloak({ store: memoryStore }, kcConfig);

function adminOnly(token, request) {
return token.hasRole(`realm:${ADMIN_ROLE}`);

function isAuthenticated(token, request) {
return token.hasRole(`realm:${ADMIN_ROLE}`) || token.hasRole(`realm:${USER_ROLE}`);

secret: process.env.APP_SECRET || 'BV&%R*BD66JH',
resave: false,
saveUninitialized: true,
store: memoryStore

app.use( keycloak.middleware() );


Setup REST endpoint and server

app.get('/public', (req, res) => {
'message': "This is a public enpoint which can be accessed by anonymous users",

app.get('/secured', [keycloak.protect(isAuthenticated)], (req, res) => {
'message': "This is a secured enpoint which can be accessed by any authenticated user",

app.get('/secured-admin', [keycloak.protect(adminOnly)], (req, res) => {
'message': "This is a secured enpoint which can be accessed only by any authenticated user with role admin",

app.listen(PORT, (error) => {
if (!error) {
console.log("Server is Successfully Running, and App is listening on port " + PORT)
else {
console.log("Error occurred, server can't start", error);

Update package.json scripts to run server

  • Update the content in the scripts section of package.json as below. It will help you run your express server in both development and production mode
  "scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
  • Start your express server in development mode(auto-reload on file change) using the below command
npm run dev

Testing your REST APIs

Public Endpoint— http://localhost:3000/public

  • Even without an authentication token, this endpoint will fetch a response.

Secured Endpoint — http://localhost:3000/secured

  • Without a token, you should get an authentication error
  • Let’s set up the Authorization tab to generate a token using the Configure New Token section. You can use the values below.
Token Name - secure-express-service
Grant type - Password Credentials
Access Token URL - http://localhost:8080/realms/master/protocol/openid-connect/token
Client ID - secure-express-service
Username -
Password -
Client Authentication - Send as basic auth header
  • Click on Get New Access Token, then Proceed, then Use Token
  • Now fire the /secured rest endpoint again, and you will get a successful response.

Secured Admin Endpoint — http://localhost:3000/secured-admin

  • If you try to access the endpoint without any token — Auth error
  • If you try to access the endpoint with the token from — Auth error
  • If you try to access the endpoint with the token from — Success

You can find the GitHub repository here for reference.

Happy learning and happy coding!