Leon_Rickert
Leon_Rickert

Reputation: 31

TypeError: Cannot read property 'keycloak-token' of undefined

I know there already are a lot of questions here like this, but none really helped me really since I'm a Junior Developer.

I am currently trying to completely just reproduce the following article: https://medium.com/devops-dudes/secure-front-end-react-js-and-back-end-node-js-express-rest-api-with-keycloak-daf159f0a94e

In there One tries to secure a Frontend with React JS and a Node.js Backend (Express Rest API) with Keylcoak.

But somehow if I try to start the node-microservices app my console keeps showing me "Initializing Keycloak" and if I try to access an endpoint in my browser it says:

TypeError: Cannot read property 'keycloak-token' of undefined

What did I do wrong?

Node-Microservices Code:

index.js

const express = require('express');
var router = express.Router();
var app = express();

const keycloak = require('./keycloak-config.js').initKeycloak();
app.use(keycloak.middleware());

router.get('/user', keycloak.protect('user'), function (req, res) {
    res.send("Hello User");
});

router.get('/admin', keycloak.protect('admin'), function (req, res) {
    res.send("Hello Admin");
});

router.get('/all', keycloak.protect(['user', 'admin']), function (req, res) {
    res.send("Hello All");
});

app.get('/', function (req, res) {
    res.send("Server is up!");
});

app.listen(8081);

keycloak-config.js

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

let keycloak;

var keycloakConfig = {
    "realm": "Demo-Realm",
    "bearer-only": true,
    "auth-server-url": "http://localhost:8080/auth/",
    "ssl-required": "external",
    "resource": "node-microservice",
    "verify-token-audience": true,
    "use-resource-role-mappings": true,
    "confidential-port": 0,
    "realmPublicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1SrR985UGLhBlCReW1p9ypcKbQhjHXDqS3DK78ihqGxLiwNWWsG/ilwD54HbxMjcVIl6hLXZbpd85oAr6HCSjRm8D6HGP6AVfva7s6pQcXmNWIeFGhwOSM/k2rjXkVGpCu3Yhg+Fnx03zA/nSlybhyYJrt/EftbjhCVO58WnAhEY8ytBHZQws+I85BzstClm3dSXj9EiWea6pqB7vpYkMy/nGUBgfOFn30Hqa2Pp7Dxkgd7+G/xRN2JDbg09etgZzt9kXVs1X6LbwAWG60qeNF2ZMCHTZeiHi0FRM7d7irRrc68orrFiEg2Gp7u3urr2ss4JOwSWe9QK/l3eZ3XS6QIDAQAB"
  };

  function initKeycloak() {
      if(keycloak) {
          console.log("Returning existing Keycloak instance!");
          return keycloak;
      }
      else {
          console.log("Initializing Keycloak...");
          var memoryStore = new session.MemoryStore();
          keycloak = new Keycloak({
              store: memoryStore,
              secret: 'any_key',
              resave: false,
              saveUnitialized: true
          }, keycloakConfig);
          return keycloak;
      }
  }

  module.exports = {
      initKeycloak
  };

Upvotes: 2

Views: 2603

Answers (1)

damnedOperator
damnedOperator

Reputation: 218

EDIT:

You need to do it like the solution the documentation proposes, as otherwise the middleware will not find the keycloak connection.

--

I had a brief look on the medium article you linked and it seems like the article uses a complicated approach to securing your express routes.

Have a look at the Official documentation of the NodeJS adapter for Keycloak (keycloak-connect), it's much, much simpler than described in the article to configure and use that way. What the initKeycloak() is doing is unneccessarily mimicking the behaviour of the frontend keycloak.js, which indeed ships a initKeycloak method to initialize Keycloak authorization services at the frontend. For Node applications, just initialize keycloak once in your index.js and you're good to go.

I have my service running with injected Kubernetes secrets, that's why all the environment variables and am setting up keycloak at the top of my index.ts like that:

Example

import express from 'express';
import pgSession from 'connect-pg-simple';
import Keycloak from 'keycloak-connect';

const app = express();

const pgSessionInit = pgSession(session);

const pgSessionStore = new pgSessionInit({
    pool: pool,
    tableName: 'session',
    schemaName: 'foo',
    createTableIfMissing: true,
});

app.use(session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    store: pgSessionStore
}))

const keycloak = new Keycloak({
    store: pgSessionStore
});

// RequestHandler and Route definitions after this point

On a side note: It helps us a lot to include stack traces, so that we can better understand your problem and point you in the right direction. Node has an additional property on its Error object called "stack".

try{
    // some code producing an Error
}catch(e: unknown){
    if(e instanceof Error){
         console.error(e, e.stack); // Retrieve Error Message and stack
    }
}

Upvotes: 1

Related Questions