Search code examples
node.jskeycloakpostgraphile

How to authenticate keycloak token using node js that calls postgraphile?


I'm new on node js, and the company that i work for needs a proof of concept about postgraphile, the situation is this:

  1. I created a node js mini server that uses postgraphile to access the data on postgres
  2. The mini server works fine and can return data and also can use mutations.
  3. I used keycloak-connect to try to access keycloak to authenticate the token from the request that is sent by postman but there is a problem.
  4. If the token is valid or not it does not matter for the mini server, the only thing that seems to matter is that is a bearer token.

I tried to use other plugins (like keycloak-nodejs-connect, keycloak-verify, etc) but the result is the same, i also changed my code to use the examples in the documentation of those plugins but nothing.

This is my code: (keycloak-config.js file)

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

let _keycloak;

var keycloakConfig = {
    clientId: 'type credential',
    bearerOnly: true,
    serverUrl: 'our company server',
    realm: 'the test realm',
    grantType: "client_credentials",
    credentials: {
        secret: 'our secret'
    }
};

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

        return _keycloak;
    }
}

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

    return _keycloak;
}

module.exports = {
    initKeycloak,
    getKeycloak
};

My Index.js file:

const express = require('express')
const bodyParser = require('body-parser')
const postgraphile = require('./postgraphile')
const app = express()

const keycloak = require('../config/keycloak-config').initKeycloak()

var router = express.Router();

app.set( 'trust proxy', true );
app.use(keycloak.middleware());
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(postgraphile);

app.get('/', keycloak.checkSso(), (req, res) => {
    res.send('success');
    } );

var server = app.listen(8080, () => console.log(`Server running on port ${8080}`));

Also I used this code to get the token and use the keycloak-verify plugin but got nothing:

router.get('/',keycloak.protect(),function(req, res, next) {
    var token=req.headers['authorization'];
    console.log(token);

    try {
        let user = keycloak.jwt.verify(token);
        console.log(user.isExpired());
    } catch (error) {
        console.error(error);
    }
})

I know that I lack the knowledge because I am a backend (C#) developer, can somebody help me with this?, thanks in advance.


Solution

  • I found the answer to my problem:

    const express = require("express");
    const request = require("request");
    var keycloakConfig = require('../AuthOnly/config/keycloak-config').keycloakConfig;
    const postgraphile = require('./postgraphile');
    
    const app = express();
    
    const keycloakHost = keycloakConfig.serverUrl;
    const realmName = keycloakConfig.realm;
    
    // check each request for a valid bearer token
    app.use((req, res, next) => {
      // assumes bearer token is passed as an authorization header
      if (req.headers.authorization) {
        // configure the request to your keycloak server
        const options = {
          method: 'GET',
          url: `${keycloakHost}/auth/realms/${realmName}/protocol/openid-connect/userinfo`,
          headers: {
            // add the token you received to the userinfo request, sent to keycloak
            Authorization: req.headers.authorization,
          },
        };
    
        // send a request to the userinfo endpoint on keycloak
        request(options, (error, response, body) => {
          if (error) throw new Error(error);
    
          // if the request status isn't "OK", the token is invalid
          if (response.statusCode !== 200) {
            res.status(401).json({
              error: `unauthorized`,
            });
          }
          // the token is valid pass request onto your next function
          else {
            next();
          }
        });
      } else {
        // there is no token, don't process request further
        res.status(401).json({
        error: `unauthorized`,
      });
    }});
    
    app.use(postgraphile);
    
    app.listen(8080);