Keycloak Login and User Model with custom data from external REST API

I’m new to keycloak (and a Java newbie overall, as I try to stay away from it whenever possible) and I’m facing an issue with Keycloak which I don’t know/understand how to solve.

What am I trying to do:

As I’m trying to create an SSO scheme across multiple applications I develop, I’ve settled on OIDC and so what I’m doing is trying to transform the information from a REST API and generate a JWT which includes some custom claims, so that every “client” I have uses a JWT in the same exact format, differing only on the specific provider/kid.

At first, I inherited some code which includes a User Federation Provider and a ProtocolMapper (which somehow don’t seem to be linked, nor do I understand how I should “link” the two but maybe that’s an easy thing to solve?).

The Protocol Mapper is mostly working, but I have a huge issue with being able to retrieve the “custom” user information to set on the custom claims.

The issue:

So, I have a (remote) REST API that provides functionalities such as Login and UserDetails.

  • Login provides an auth token (a JSESSION) which comes in the form of a Cookie. If this API returns an OK, then the user is valid and logged in and we call this login method from the isValid method on the Storage Provider.
  • UserDetails returns the user information (name, phone, permissions, etc) and requires a valid JSESSION token in order to work, which is the one retrieved from the Login call. It doesn’t work without it.

I’m using this REST API as the de facto validator of the users. If this API says all is OK, then Keycloak should generate a JWT and proceed with its normal operation.

However, currently I have to set a static final variable (and a getter) on the code of the Custom Storage Provider so that I can call the getter once I get to the Protocol Mapper tranformAccessToken override. This is, of course, not thread-safe and will cause issues with users getting tokens that do not belong to them.

I need to fix this and have been unable to, so far.

I have this (sample) code available at GitHub - CelsoSantos/keycloak-labs-base, which represents the code I inherited and which is my “starting point” for this discussion.

What have I done to solve it:

I’ve been reading A LOT of documentation, websites, forums and so on regarding Custom User Models, Federated User Storage, Protocol Mappers, Custom User Attributed, etc and ended up more confused than when I started. By following some examples or code on GitHub whenever pointed to, I ended up creating something that I feel is overly complicated and still doesn’t answer my needs, so I went a step back and introduced only a UserModelFactory, hoping this would be enough to solve the issue and yet, I think I’m still not doing something right as I can’t get the non-standard information from this.

I also have this code available at CelsoSantos/keycloak-labs (can’t put more than 2 links yet :frowning:)

Another thing I’ve tried, by following the example at keycloak-extensions-demo/user-provider at main · dasniko/keycloak-extensions-demo · GitHub and, again, my implementation “blows up” because I can’t get User Info without logging in first. This code I do not have available at github but follows the same pattern of this demo.

The question(s):

I’m lost. The more I read and the more code I try, the more I get confused.

All I want to do I to be able to store some user data (the one I get from the REST API) on the Keycloak user data and then retrieve it whenever I need to generate the JWT with the custom claims. I don’t even need to see it when going to Keycloak’s admin panel/user info.

The way I look at it, keycloak should:

  1. Try to get the user from some form of local storage (maybe in-memory is enough)
  2. If the user already had logged in, retrieve it from said local storage, otherwise, step 3
  3. If the user doesn’t exist locally (had not yet logged in), proceed to the login page, get the username/password, call the REST Login, and login the user on keycloak (isValid maybe?), get the token and call the REST API UserDetails to get the user data and store it.
  4. Generate JWT with custom claims and proceed

I have, so far, been unable to do so and don’t know where to look anymore.

So, I guess these are my questions:

  • What am I doing wrong?
  • Should I have a very complex Federated Storage Provider?
  • Is the User Model Factory enough and I’m just not using it right?
  • The approach on the dasniko GH repo should be the one I should follow? The “flow” of the code doesn’t seem correct (the adapter needs user info before the user has been logged in).
  • Did I totally misunderstand the docs and blogs and I should be using some other technique/SPI?