Express-jwt and Keycloak: how I did not use official Keycloak library

Problem

We have many microservices that run on multiple deployments. I wanted to add security by using Keycloak with the help of JWT.

Solution

One of the earliest solution was to use Keycloak Js Adapter. Yet, Keycloak JS adapter requires following:

var keycloakConfig = {
clientId: 'nodejs-microservice',
bearerOnly: true,
serverUrl: 'http://localhost:8080/auth',
realm: 'Demo-Realm',
credentials: {
secret: '62c99f7c-da55-48fb-ae4e-a27f132546b7'
}
};

which seems cumbersome way of doing this.

I thought there must be more simple way, I just wanted to validate requests.

That’s why I liked Spring Boot approach which is:

  • include package
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
  • add one line config
spring.security.oauth2.resourceserver.jwt.issuer-uri = http://localhost:8080/auth/realms/appsdeveloperblog

At start, it fetches makes request to issuer-uri which has response like this

{
"realm": "appsdeveloperblog",
"public_key": "...",
"token-service": "http://localhost:8080/auth/appsdeveloperblog/master/protocol/openid-connect",
"account-service": "http://localhost:8080/realms/appsdeveloperblog/account",
"tokens-not-before": 0
}

and stores public_key which is used to validate JWT tokens. It doesn't make request each time to verify JWT.
As result, any request is validated and working out of box.

So I wanted to replicate this on NodeJS.

I started with express-jwt and simple example was like this

var jwt = require('express-jwt');app.get('/protected',
jwt({ secret: 'shhhhhhared-secret', algorithms: ['HS256'] }),
function(req, res) {
if (!req.user.admin) return res.sendStatus(401);
res.sendStatus(200);
});
//Or with public key, shortenedvar publicKey = fs.readFileSync('/path/to/public.pub');
jwt({ secret: publicKey, algorithms: ['RS256'] });

However it was problem for us to provide public key because

  • we have multiple deployments
  • each deployment has its own Keycloak.

We couldn’t maintain this so I decided to implement like in Spring Boot.

With the help sync-request package:

const res = request('GET', 'http://localhost:8080/auth/realms/appsdeveloperblog');
const response = JSON.parse(res.getBody().toString());
const publicKey = `-----BEGIN PUBLIC KEY-----\r\n${response.public_key}\r\n-----END PUBLIC KEY-----`;
app.use(jwt({ secret: publicKey, algorithms: ['RS256'] }));

I achieved on-start fetch of public key without cumbersome settings on NodeJS.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store