0

I had previously built a Keycloak Express boilerplate using the node client adapter (keycloak-connect). However, Keycloak has deprecated their client adapters for node, so I looked for a solution and found a suggestion to integrate Passport with the OpenID Client for Keycloak on this Stack Overflow question (NodeJS + Keycloak without express). I followed the instructions in this Medium article (https://medium.com/keycloak/keycloak-express-openid-client-fabea857f11f) to build my Keycloak Express boilerplate, but it didn't work for me. My register and login endpoints are functioning properly, but my protected route is not working as expected.Could anyone provide a template or guide on how to properly configure Passport.js? I have attached my current code for reference.

import express, {
    Express,
    Request,
    Response
} from 'express';
import 'reflect-metadata';
import bodyparser from 'body-parser';
import userRouter from './api/routes/userRoutes';
import expressSession from 'express-session';
import cookieParser from 'cookie-parser'
import connection from './database/connection';
import cors from 'cors';
import { corsOptions } from './config/corsOptions';
import { credentials } from './api/middlewares/credentials';
import { Issuer, Strategy } from 'openid-client';
import passport from 'passport';
import config from './config';
import KeycloakStrategy from "@exlinc/keycloak-passport";

//GETTING PORT FROM .ENV FILE:
const PORT = config.port || 3000;
const app: Express = express();

var memoryStore = new expressSession.MemoryStore();
app.use(
    expressSession({
    secret: 'another_long_secret',
    resave: false,
    saveUninitialized: true,
    store: memoryStore
    })
);

app.use(passport.initialize());
app.use(passport.authenticate('session'));


Issuer.discover('http://localhost:8080/realms/Demo').then(function (oidcIssuer) {
    var client = new oidcIssuer.Client({
        client_id: 'keycloak_practice',
        client_secret: 'hkvogjo7jziNV3X4hR2rUILQikNKHpSL',
        redirect_uris: ['http://localhost:8000/private'],
        response_types: ['code'],
    })

    passport.use('oidc', new Strategy({client}, (tokenSet, userinfo, done)=>{
        return done(null, tokenSet.claims());
    })
)
});
passport.serializeUser(function(user, done) {
    done(null, user);
  });
passport.deserializeUser(function(user, done) {
    done(null, user);
});

app.use(credentials)
app.use(cors(corsOptions));
app.use(express.json());
app.use((bodyparser.urlencoded({ extended: true })));
app.use(cookieParser());

//CONNECTING TO DATABASE:
connection();

app.use('/user', userRouter);

//CONNECTION TO PORT:
app.listen(PORT, () => {
  console.log(`This application is listening on port ${PORT}`);
});

Here userRouter.ts

import express, { Router } from 'express';
import { loginUserController, logoutUserController, protectedRouteController, refreshTokenController, registerUserController } from '../controllers/userController';
import passport from 'passport';

const userRouter: Router = express.Router();

userRouter.post('/register', registerUserController);
userRouter.post('/login', loginUserController);
userRouter.get('/refreshToken', refreshTokenController);
userRouter.post('/logout', logoutUserController);

//protected route 
userRouter.get('/private',  passport.authenticate('oidc'),protectedRouteController);

// keycloak.protect()
export default userRouter;

Request for guidance on properly configuring Passport.js. Could anyone share a template or step-by-step guide on how to set up Passport.js for keycloak effectively?

1 Answers1

0

It's good to see you're preparing for it.
Keycloak is considering openid-client as a good alternative for node.js as well, so it's a good choice.

I recently followed the same guide to migrate a project and it was a painless transition.

It's hard to tell exactly what your controllers are doing, so I'm making a few assumptions here.
You're defining /private in userRouter.ts that has the base /user, and the path resolves to http://localhost:8000/user/private. Your redirect uri is http://localhost:8000/private. Unless I'm misremembering how routers work, I think that's your culprit.

If that's not it, you could get more information by examining the result from the callback.
My bet is you would see a CODE_TO_TOKEN_ERROR or something similar.

ShadowScripter
  • 7,314
  • 4
  • 36
  • 54