Auth adapters - keycloak and oauth2

@gdac greg
Fri, 16 Jan 2026 14:57:25 +0000

Hello,
I’m trying to use keycloak authentication in parse-server. I think there are multiple problems in the implementation of the adapter.

In src/Adapters/Auth/keycloak.js :

 * @param {Array} [authData.roles] - The roles assigned to the user in Keycloak (optional).
 * @param {Array} [authData.groups] - The groups assigned to the user in Keycloak (optional).

means groups and roles keys in authData are optional.
But in the code :

    if (
      response &&
      response.data &&
      response.data.sub == id &&
      arraysEqual(response.data.roles, roles) &&
      arraysEqual(response.data.groups, groups)
    ) {
      return;
    }

there are calls to arraysEqual for roles and groups, which are undefined if not present in authData.

There should be something like :

    if (
      response &&
      response.data &&
      response.data.sub == id &&
      (typeof roles === undefined || arraysEqual(response.data.roles, roles)) &&
      (typeof groups === undefined || rraysEqual(response.data.groups, groups))
    ) {
      return;
    }

the check is made against response.data

But after some tries, I found out that in my responses from keycloak userinfo endpoint, I didn’t get a data key. In fact it works with :

    if (
      response &&
      response.sub == id &&
      (typeof roles === undefined || arraysEqual(response.roles, roles)) &&
      (typeof groups === undefined || arraysEqual(response.groups, groups))
    ) {
      return;
    }

I used this code in a custom auth adapter, but it might be useful to fix it upstream.

In fact I have also tried to use oauth2 adapter, and unfortunately I think it does not work.

The code in src/Adapters/Auth/oauth2.js :

specifies

 * {
 *   "auth": {
 *     "oauth2Provider": {
         ...
 *   }
 * }
 *

and there is this implementation

    const response = await fetch(this.tokenIntrospectionEndpointUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        ...(this.authorizationHeader && {
          Authorization: this.authorizationHeader
        })
      },
      body: new URLSearchParams({
        token: accessToken,
      })
    });

but it didn’t work at all, response allways returned with ‘401: Unthauthorized’.

I got it working with

 * {
 *   "auth": {
 *     "oauth2": {
         ...
 *   }
 * }
 *

and this implementation

    const response = await fetch(this.tokenIntrospectionEndpointUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        ...(this.authorizationHeader && {
          Authorization: this.authorizationHeader
        })
      },
      body: new URLSearchParams({
        token: accessToken,
        client_secret: "***redacted***",
        client_id: "myclient"
      })
    });

with a Keycloak client myclient configured for client authentication.

Any opinion on the matter ? I believe keycloak and oath2 auth providers are not widely used as I did not find a lot of help on this subject.