400 with keycloak-admin and connecting via client-id and client-secret, in NodeJS?

I have created a client in keycloak that will be used by our staff account server. We then try connecting to our keycloak server from a NodeJS app, using ‘keycloak-admin’, but in doing so we get a 400 error.

In Keycloak, for our client, the settings of note:

  • Settings:
    • Client Protocol: openid-connect
    • Access Type: bearer-only
  • Credentials:
    • Client Authenticator: Client Id and Secret

Then in the NodeJS app which uses ‘keycloak-admin’:

async accessContext () {
  const kcAdminClient = new KcAdminClient({
    baseUrl: this.baseUrl,
    realmName: this.realm
  });

  // Not the real client secret
  await kcAdminClient.auth({
    grantType: 'client_credentials',
    clientId: 'staff-account-server',
    clientSecret: '0f65bbed-0000-0000-ad1c-19a4085e10c0'
  });

  return kcAdminClient;
}

In doing this I get the following error:

Error: {"message":"Request failed with status code 400","name":"Error","stack":"Error: Request failed with status code 400\n    at createError (/Users/ajmas/Development/my-project/node_modules/keycloak-admin/node_modules/axios/lib/core/createError.js:16:15)\n    at settle (/Users/ajmas/Development/my-project/node_modules/keycloak-admin/node_modules/axios/lib/core/settle.js:17:12)\n    at IncomingMessage.handleStreamEnd (/Users/ajmas/Development/my-project/node_modules/keycloak-admin/node_modules/axios/lib/adapters/http.js:260:11)\n    at IncomingMessage.emit (events.js:327:22)\n    at endReadableNT (_stream_readable.js:1327:12)\n    at processTicksAndRejections (internal/process/task_queues.js:80:21)","config":{"url":"https://keycloak-test.somedomain.com/auth/realms/master/protocol/openid-connect/token","method":"post","data":"client_id=staff-server&grant_type=client_credentials","headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/x-www-form-urlencoded","User-Agent":"axios/0.21.1","Content-Length":52},"auth":{"username":"staff-account-server","password":"0f65bbed-0000-0000-ad1c-19a4085e10c0"},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"maxBodyLength":-1}}      
Error: Request failed with status code 400
    at createError (/Users/ajmas/Development/my-project/node_modules/keycloak-admin/node_modules/axios/lib/core/createError.js:16:15)
    at settle (/Users/ajmas/Development/my-project/node_modules/keycloak-admin/node_modules/axios/lib/core/settle.js:17:12)
    at IncomingMessage.handleStreamEnd (/Users/ajmas/Development/my-project/node_modules/keycloak-admin/node_modules/axios/lib/adapters/http.js:260:11)
    at IncomingMessage.emit (events.js:327:22)
    at endReadableNT (_stream_readable.js:1327:12)
    at processTicksAndRejections (internal/process/task_queues.js:80:21)        

BTW While I can work around with a grant type of password, for basic admin connectivity, the passport adapter we are planning to use, @exlinc/keycloak-passport, would have issues, since this needs client id and client secret.

I am suspecting there are some configurations I probably missed on the Keycloak side, but I am not sure what they are? Can anyone suggest what I should be looking at?

As you can see in the logs, it is pointing to master realm which doesn’t have your client. It is happening because this.realm is not pointing to your realm. Try to change this and mention your realm name once like below:

 async accessContext () {
   const kcAdminClient = new KcAdminClient({
     baseUrl: this.baseUrl,
     realmName: 'my-realm'
   });

// Not the real client secret
  await kcAdminClient.auth({
    grantType: 'client_credentials',
    clientId: 'staff-account-server',
    clientSecret: '0f65bbed-0000-0000-ad1c-19a4085e10c0'
  });

  return kcAdminClient;
}