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:
- Importing Dependencies: The application imports the required modules, including Express and Keycloak.
- Creating Express App: Then, we create an instance of the Express application.
- 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. - 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. - 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.
- The
- 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.
- 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 variableadminClient
. - The
await adminClient.auth(config.adminClient)
line performs an asynchronous operation. It calls theauth
method on theadminClient
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 theadminClient
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:
Then, you should be able to see the following Users as part of your Realm:
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