keycloak-nodejs-connect express.js app behind reverse proxy

1k views Asked by At

I have created a node.js app with Keycloak middleware for Express JS, which proverbially "works on my computer".

const Keycloak = require('keycloak-connect')
const express = require('express')
const session = require('express-session')
const app = express()

const LOGIN_PATH = '/login'
const LOGOUT_PATH = '/logout'
const SESSION_STORE_PASS = '123456789012345678901234567890!!!'

const server = app.listen(3000, function () {
    const host = server.address().address
    const port = server.address().port
    console.log('Example app listening at http://%s:%s', host, port)
})

app.get('/', function (req, res) {
    res.redirect(LOGIN_PATH)
})

// Create a session-store to be used by both the express-session
// middleware and the keycloak middleware.
const memoryStore = new session.MemoryStore()
app.use(session({
    secret: SESSION_STORE_PASS,
    resave: false,
    saveUninitialized: true,
    store: memoryStore
}))

const kcOptions = {
    "realm": "nodejs-example",
    "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
    "auth-server-url": "http://localhost:8080/auth",
    "ssl-required": "external",
    "resource": "nodejs-connect",
    "public-client": true
}
console.log("Starting Keycloak connector with options: ", kcOptions)
const keycloak = new Keycloak({store: memoryStore}, kcOptions)

app.use(keycloak.middleware({
    logout: LOGOUT_PATH, // <-- this is supposed to delete the session and log you out from KC as well
    admin: '/'
}))

app.get('/login', keycloak.protect(), async function (req, res) {
    let token
    try {
        const grant = await keycloak.getGrant(req, res)
        token = grant.access_token
        console.log(`Found token ${token}`)
    } catch (e) {
        console.log("Unable to find the token in KC response ", req.session)
        throw new Error(e)
    }
    const userProfile = await keycloak.grantManager.userInfo(token)
    console.log("Found user profile:", userProfile)

    res.header("Content-Type", 'application/json')
    return res.send(JSON.stringify(userProfile, null, 4))
})

This app listens on port 3000, but the problem is that browsers are going to reach it through the reverse proxy (port 80). And there is no way for me to make the middleware send the correct "redirect_uri" query parameter to Keycloak. It always puts a URL with same port 3000 where the local server is listening.

I found redirection-url setting in the documentation, but I found no evidence of that string in the Github repository.

1

There are 1 answers

2
sscarduzio On

From some code analisys in the keycloak-nodejs-connect repository, the redirect_uri query parameter is merely assembled from the incoming request, assuming the app is directly reachable.

And this issue affects both login and logout phase. Therefore - unfurtunately - there's no way to use this library in a realistic situation (where a reverse proxy, or load balancer is involved).

Not to mention the strange disconnect between features described in the documentation and the actually implemented ones.