Reputation: 31
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
Reputation: 218
EDIT:
--
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:
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