0
votes

I've a React app that uses Keycloak as a authentication service. Also I've a Nodejs rest api with endpoints secured by keycloak, so the React app sends JWT when needs call an api. In Keycloak admin console I created 1 public client with users and roles.

All works fine, but the only problems is when a I logout through admin console, or from my React application berfore that expiration time, I still can call to my app with these token.

Why my backend app doesn't validate the token with server?

My node app uses keycloak-node-connect adapter and my keycloak.json is:

{
    "client-id": "my-public-client",
    "bearer-only": true,
    "auth-server-url": "http://localhost:8180/auth",
    "realm": "my-realm"    
}
1
i've the same issue, did you find a solution ? thanks. Cordially.mca
I solved my problem using keycloak endpoint userinfo suggested in stackoverflow.com/questions/48274251/…Hector
@mickael-camelot I updated the above question with my solutionHector
@Hector Pls, Don't do that. Just add a new answer and put the code there and set it as accepteddreamcrash
thank you for your suggestion, I added a new answer with my solutionHector

1 Answers

0
votes

Solved

I can solved my probleam like suggested in Keycloak: Access token validation end point

keycloak.config.js

var session = require('express-session');
var Keycloak = require('keycloak-connect');
var request = require('request');
const createError = require('http-errors');

let _keycloak;

var memoryStore = new session.MemoryStore();

function initKeycloak() {
    if (_keycloak) {
        console.log("Trying to init Keycloak again!");
        return _keycloak;
    }
    else {
        console.log("Initializing Keycloak...");
        _keycloak = new Keycloak({ store: memoryStore });
        return _keycloak;
    }
}

function getKeycloak() {
    if (!_keycloak) {
        console.error('Keycloak has not been initialized. Please called init first.');
    }
    return _keycloak;
}

async function validateTokenKeycloak(req, res, next) {
    if (req.kauth && req.kauth.grant) {        
        console.log('--- Verify token ---');
        try {
            var result = await _keycloak.grantManager.userInfo(req.kauth.grant.access_token);
            //var result = await _keycloak.grantManager.validateAccessToken(req.kauth.grant.access_token);
            if(!result) {
                console.log(`result:`,  result); 
                throw Error('Invalid Token');
            }                        
        } catch (error) {
            console.log(`Error: ${error.message}`);
            return next(createError.Unauthorized());
        }
    }
    next();  
}

module.exports = {
    memoryStore,
    initKeycloak,
    getKeycloak,
    validateTokenKeycloak
};

app.js

const express = require('express');
const createError = require('http-errors');
const dotenv = require('dotenv').config();
const session = require('express-session');
const keycloakConfig = require('./config/keycloak.config');

const app = express();

// Keycloak
app.use(session({
    secret: 'secret',
    resave: false,
    saveUninitialized: true,
    store: keycloakConfig.memoryStore
}));
  
const keycloak = keycloakConfig.initKeycloak();
  
app.use(keycloak.middleware());

app.use(keycloakConfig.validateTokenKeycloak);

app.use("/health", require('./routes/health.route'));

// 404 handler and pass to error handler
app.use((req, res, next) => {    
    next(createError(404, 'Not found'));
});

// Error Handler
app.use((err, req, res, next) => {  
    res.status(err.status || 500);
    res.send({
        error : {
            status : err.status || 500,
            message : err.message
        }
    });
});

const PORT = process.env.PORT || 3000;


app.listen(PORT, () => {
    console.log(`Server starter on port ${PORT}`);
});