Connecting to Keycloak from Node.js Adapter

In this tutorial, we’ll learn how to connect to Keycloak from a Node.js application using the keycloak-connect Adapter. We’ll walk through setting up a basic Express application and protecting routes with Keycloak authentication and authorization.

Keycloak API for Node.js

This article assumes you are familiar with Keycloak. If this is not the case, you can begin with this introduction article: Keycloak tutorial for beginners . Also, it is assumed that you have a basic knowledge of Node.js and the Express Framework.

In this tutorial, we will go through a basic quickstart Example which is available in the Keycloak GitHub Repository.

The first element of a Node.js project is the package declaration which you keep in the package.json file. This file acts as a manifest file, storing essential information about your project such as:

  • Project Metadata: name, version, description and license of your project
  • Dependency Management: Lists the external libraries and scripts your project requires to function. These libraries are downloaded from the npm Package Registry (or a similar source) during installation.

You can init a Node.js project with:

npm init -y

This will create a basic package.json. To work with Keycloak, we need to include the following core Keycloak dependencies in our project:

  • @keycloak/keycloak-admin-client : Provides functionalities to interact with the Keycloak server’s administrative API. This allows your application to perform administrative tasks on the Keycloak server.
  • keycloak-connect: Acts as a middleware for the Express framework. It enables integrating Keycloak with your Node.js application for user authentication and authorization.
{
  "name": "keycloak-resource-server",
  "type": "module",
  "scripts": {
    "start": "node app.js",
    "test": "npm run create-realm && node --test && npm run delete-realm",
    "create-realm": "node scripts/create-realm.js",
    "delete-realm": "node scripts/delete-realm.js"
  },
  "dependencies": {
    "@keycloak/keycloak-admin-client": "24.0.4",
    "express": "^4.18.2",
    "keycloak-connect": "24.0.4"
  },
  "devDependencies": {
    "keycloak-request-token": "^0.1.0"
  }
}

As you can see, the package.json also includes two scripts to create and delete a Keycloak Realm. We will first discuss about the main application file, which is app.js.

Coding the app.js File

In a Node.js application, the app.js file (or whichever filename you define in your package.json) it’s where your Node.js application execution begins. Within this file, we will create a REST Controller that connects to a Keycloak server:

import express from 'express';
import Keycloak from 'keycloak-connect';

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

// Middleware configuration loaded from keycloak.json file.
const keycloak = new Keycloak({});

app.use(keycloak.middleware());

app.get('/public', (req, res) => {
  res.json({message: 'public'});
});

app.get('/secured', keycloak.protect('realm:user'), (req, res) => {
  res.json({message: 'secured'});
});

app.get('/admin', keycloak.protect('realm:admin'), (req, res) => {
  res.json({message: 'admin'});
});

app.use('*', (req, res) => {
  res.send('Not found!');
});

app.listen(port, () => {
  console.log(`Listening on port ${port}.`);
});

Let’s break down the code and explain each part:

  1. Importing Dependencies: The application imports the required modules, including Express and Keycloak.
  2. Creating Express App: Then, we create an instance of the Express application.
  3. Middleware Configuration: The Keycloak middleware is initialized with default configuration loaded from the keycloak.json file. This file typically contains information about the Keycloak server, such as the realm name, client ID, client secret, etc.
  4. Middleware Usage: The Keycloak middleware is applied to the Express application using the app.use() method. This middleware is responsible for handling authentication and authorization for protected routes.
  5. Defining Routes:
    • The /public route is defined to serve public content without any authentication or authorization.
    • The /secured route is protected using Keycloak and is accessible only to users authenticated in the ‘realm:user’ realm.
    • The /admin route is protected using Keycloak and is accessible only to users authenticated in the ‘realm:admin’ realm.
  6. Not Found Route: A catch-all route is defined to handle requests for routes that are not explicitly defined. It responds with a ‘Not found!’ message.
  7. Starting the Server: The Express application listens on the specified port (3000 in this case) for incoming requests.

Coding the Keycloak Admin Client

To perform Authentication with Keycloak, we will use the following keycloak-admin-client.js . This file sets up an authenticated Keycloak admin client ready to be used for administrative tasks on your Keycloak server.

import KcAdminClient from '@keycloak/keycloak-admin-client';
import config from '../config/config.js';

const adminClient = new KcAdminClient(config.adminClient)

await adminClient.auth(config.adminClient);

export default adminClient;
  • We create an instance of KcAdminClient and we assign it to the variable adminClient.
  • The await adminClient.auth(config.adminClient) line performs an asynchronous operation. It calls the auth method on the adminClient object, passing the same configuration object (config.adminClient). This method uses the provided credentials to authenticate with the Keycloak server and obtain an access token for further administrative operations.
  • Finally, the export default adminClient statement makes the adminClient object available for use in other parts of your application.

Importing a Keycloak Realm

To run this example application, a sample quickstart Realm is available in the config folder of this example. We can either import if from Keycloak or we can import it from the adminClient:

import { readFileSync } from 'node:fs';
import adminClient from './keycloak-admin-client.js';

await adminClient.realms.create(
  JSON.parse(readFileSync(new URL('../config/realm-import.json', import.meta.url), 'utf8'))
);

The code calls the adminClient.realms.create method asynchronously (await). This method is part of the keycloak-admin-client library and is specifically designed for creating new realms in your Keycloak server.

Adding the keycloak.json Adapter

The keycloak.json file provides essential configuration details for keycloak-connect to establish a secure connection with your Keycloak server and perform user authentication for your Node.js application.

{
  "realm": "quickstart",
  "bearer-only": true,
  "auth-server-url": "http://127.0.0.1:8180",
  "ssl-required": "external",
  "resource": "resource-server"
}

From the above file, we define as target Server the URL http://127.0.0.1:8180 where the ClientId “resource-server” runs in the Realm “quickstart“. The bearer-only setting to true validates only access tokens received in the request authorization header and skip other token types.

Starting Keycloak

Firstly, we need to start Keycloak. The simplest way to do it is by running its Docker Image:

docker run --rm --name keycloak   -e KEYCLOAK_ADMIN=admin   -e KEYCLOAK_ADMIN_PASSWORD=admin   --network=host   quay.io/keycloak/keycloak    start-dev   --http-port=8180

The above docker command will start the latest Keycloak Image on port 8180, enabling admin access with the credentials admin/admin. You can learn more about starting Keycloak with Docker in this article: How to run Keycloak with Docker

Building and Running the Node.js application

Before we start the Node.js application, we need to install the packages defined in the package.json file. The npm install command is the primary way to install packages from the npm Package Registry (or a similar source) for your Node.js project.

npm install

Then, import the Keycloak quickstart Realm with:

npm run create-realm

Next, verify by logging into Keycloak Console, that the quickstart Realm is available. Open the browser at localhost:8180 and use admin/admin to login:

keycloak with nodejs example

Then, you should be able to see the following Users as part of your Realm:

keycloak nodejs tutorial

Finally, you can run the Node.js application with:

$ npm start

> start
> node app.js

Listening on port 3000.

As we know from package.json, the start command will trigger the app.js as Entry Point.

"start": "node app.js",

Let’s test the Endpoints! Firstly, we will test the public endpoint which does not require authentication:

curl http://localhost:3000/public

You should see the following JSON as response:

{"message":"public"}

Then, we will test one of the secured Endpoint. For example, the secured endpoint which you can invoke by users with the user role, such as “alice”.

Begin by requesting an Access Token for the User “alice”:

export access_token=$(\
curl -X POST http://127.0.0.1:8180/realms/quickstart/protocol/openid-connect/token \
-H 'content-type: application/x-www-form-urlencoded' \
-d 'client_id=test-cli' \
-d 'username=alice&password=alice&grant_type=password' | jq --raw-output '.access_token' \
)

The access token is now stored in the access_token variable. Use this variable to authenticate on the secured Endpoint:

curl http://localhost:3000/secured \
  -H "Authorization: Bearer "$access_token

A successful authentication will display the following JSON Response:

{"message":"secured"}

That’s it! You’ve successfully connected to Keycloak from a Node.js application using the keycloak-connect middleware. You can now integrate Keycloak authentication and authorization into your Node.js projects.

Conclusion

This article was a walk- through a basic example of how to use Keycloak Node.js API to connect and authenticate a simple Javascrpt application

You can find the quickstart example on GitHub here: https://github.com/keycloak/keycloak-quickstarts/tree/latest/nodejs/resource-server