Marc
Marc

Reputation: 492

keycloak-nodejs-connect: Could not obtain grant code: 400:Bad Request

Setup:

I am trying to get the demo code for keycloak-connect library to run, but failing.

Here's what I did:

index.js

var createError = require('http-errors');


var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

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

var memoryStore = new session.MemoryStore();

let keycloak = new Keycloak({ store: memoryStore });

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

app.set('trust proxy', 1); // trust first proxy
app.use(session({
    secret: 'keyboard cat',
    resave: false,
    saveUninitialized: true,
    cookie: { secure: true },
    store: memoryStore
}));

app.use( keycloak.middleware() );

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));


app.get('/$', function(req, res) {
    res.write('<a href="/secure">Secure</a>');
    res.end();
});

app.get( '/secure', keycloak.protect('realm:master'), function(req, res){
//Edit: keycloak.protect() gives the same result
    res.write("Yo!");
    res.end();
});

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

keycloak.json (copy/paste)

{
  "realm": "master",
  "auth-server-url": "http://localhost:8080/auth",
  "ssl-required": "external",
  "resource": "test",
  "public-client": true,
  "confidential-port": 0
}

package.json

{
  "name": "keycloak-test",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "cookie-parser": "~1.4.3",
    "debug": "~2.6.9",
    "express": "~4.16.0",
    "express-session": "^1.15.6",
    "http-errors": "~1.6.2",
    "keycloak-connect": "^4.7.0",
    "morgan": "~1.9.0",
    "pug": "2.0.0-beta11"
  }
}

Problem:

On accessing http://localhost:3000/secure, I am redirected to the keycloak login form, and can log in with the user credentials for the demo user.

I am then redirected back to /secure, and the website says Access denied with 403 forbidden response code. The keycloak console says

16:44:56,691 WARN  [org.keycloak.events] (default task-8) 
type=CODE_TO_TOKEN_ERROR, 
realmId=master, 
clientId=test, 
userId=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, 
ipAddress=127.0.0.1, 
error=invalid_code, 
grant_type=authorization_code, 
code_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, 
client_auth_method=client-secret

enter image description here

The node.js console says Could not obtain grant code: 400:Bad Request.

What am I doing wrong?

Upvotes: 9

Views: 8958

Answers (4)

John
John

Reputation: 11

Try to add scope to your Keycloak constructor:

let keycloak = new Keycloak({ store: memoryStore, scope: YOUR_CLIENT_ID });

Upvotes: 0

Emre
Emre

Reputation: 370

If you are running keycloak and also your backend in Docker, the keycloak url won't be localhost anymore in the config file. Your backend will try to reach its own localhost, which has a different IP address under Docker. You can check the networking settings of Docker to create a common network for your backend and keycloak, or serve both to your host machine and change auth-server-url as shown.

const keycloakConfig = {
  'confidential-port': 0,
  'auth-server-url': 'http://host.docker.internal:8080/auth',
  resource: 'my-client-id',
  'ssl-required': 'external',
  realm: 'my-realm',
  credentials: {
    secret: 'my-secret',
  },
};

Upvotes: 0

Rahul
Rahul

Reputation: 1005

The problem with this is a problem with the npm keycloak-connect package, when you install using npm install must be getting a warning which says, run npm audit.

Run npm audit --force abd rerun the app it will work. I was stuck in the same problem for a day and this thing came as a life saver for me.

run npm audit --force after an npm install.

npm install

npm audit --force

Upvotes: -1

ravthiru
ravthiru

Reputation: 9633

you are securing your resource /secure with a realm role called master

app.get( '/secure', keycloak.protect('realm:master')

you need to create master role and assign to demouser as shown below

enter image description here

Upvotes: 0

Related Questions