Open abstractj opened 2 years ago
Hi @abstractj,
I am currently starting to make the connection from our Node.js backend to the KeyCloak auth server. Do you have a hint which might be the recommended alternative? I don't want to jump on this package when it is already deprecated :)
Thanks Christian
Hi @coeing, @jonkoops has started his research about it and has more details. But it seems that right now the best alternative is https://github.com/panva/node-openid-client.
The openid-client
library is a likely recommendation for a low-level approach to the spec. For easier higher level integration we're thinking of recommending express-openid-connect
.
Feel free to try these out and let us know what your experience is.
@abstractj @jonkoops Thanks a lot for your quick suggestions! I will try those libraries and hope to remember to give you feedback :)
Any feedback @coeing about new node keycloak implementation ?
@marcoBros only to bring some clarity here, there's no "new node Keycloak implementation". The Keycloak Node.js adapter will be deprecated, and it is recommended to users to transition to another library. The library suggested is the express-openid-connect
.
Just a small update I am still in the process of gathering a list of all the features of this package so that we can provide a comprehensive overview of what possible replacement packages need to support.
Any feedback @coeing about new node keycloak implementation ?
Hi @marcoBros !
Thanks for the reminder :)
In the end we just verify the token send by the frontend with the public key from the Keycloak realm, so we can be sure that the token was created by Keycloak. There is no direct communication between Keycloak and our backend. There are some things we need in the backend, e.g. the ids of the clients the user belongs to. Those information is included in the token payload, so after verification the backend knows those information.
If anybody sees a problem with this approach, let me know! It looks like this is the most efficient way to handle access tokens that were provided by third-party services.
Cheers
If anybody sees a problem with this approach, let me know! It looks like this is the most efficient way to handle access tokens that were provided by third-party services.
When it comes to Keycloak (and OpenID in general) I'm a total beginner, so I have hard time trying to imagine how to implement this, but I need to make sure that my webservices can be used only by authenticated users or well known trusted machines (which I assume can be represented as clients in KC).
Up until now, I 've been naively taking for granted the need to use some sort of middleware, in my express app, to filter requests via KC, asking KC something like: "Here is the payload I received from my Angular client app, please tell me what roles/capabilites this user has so that I can decide if I should grant access to this resource or not".
However now that I've read (and hopefully understood) your comment, seems like my express app does not need to talk to KC at all, but it only needs to check if the payload was signed by KC and then it will find all the needed informations about the user inside the payload itself. Am I wrong?
Hi @lucrus73 ,
I can understand your thinking, this was the way I imagined it in the beginning as well. But due to the magic of asymmetric encryption your server only needs the public key of the Keycloak Realm (which can be seen publicly under https://your-keycloak-server.com/auth/realms/your-realm-name). You will have to surround the key by -----BEGIN PUBLIC KEY-----
and -----END PUBLIC KEY-----
, otherwise jwt.verify
won't like it. This is my entry in my .env
file:
KEYCLOAK_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
MIIB.....QAB
-----END PUBLIC KEY-----"
Here is my code snippet which does the verification of the token that was send by the frontend:
import jwt from "jsonwebtoken";
private validateUserToken(
token: string,
config: KeycloakConfig
): AuthUser | undefined {
try {
const result = jwt.verify(token, config.publicKey, {
algorithms: [config.algorithm],
complete: false,
});
debug(`Valid token:\n${JSON.stringify(result, undefined, 2)}`);
if (typeof result === "string") {
throw new Error(`Got invalid token payload: ${result}`);
}
const user: AuthUser = {
name: result.preferred_username || result.email,
email: result.email,
groups: result.groups,
};
return user;
} catch (error) {
return undefined;
}
}
the public key of the Keycloak Realm (which can be seen publicly under https://your-keycloak-server.com/auth/realms/your-realm-name)
In my case that page yelds a nice "We are sorry - Page not found" message... of course I replaced the placeholders with my domain and realm names.
the public key of the Keycloak Realm (which can be seen publicly under https://your-keycloak-server.com/auth/realms/your-realm-name)
In my case that page yelds a nice "We are sorry - Page not found" message... of course I replaced the placeholders with my domain and realm names.
You can also find it in the Admin Console (https://your-key-cloak-server/auth/admin/master/console
) under "Realm Settings" > "Keys" > "RS256" > "Public Key"
You can also find it in the Admin Console (
https://your-key-cloak-server/auth/admin/master/console
) under "Realm Settings" > "Keys" > "RS256" > "Public Key"
Sure, but that requires to manually copy the public key into .env. If I ever need to regenerate the keys (e.g. compromised key), then I have to remember to copy the new public key in every .env out there that's using the compromised one and do that manually. Granted: in that case I'll have bigger problems than some copy&paste extra work, but it's not only that: I also need to document the procedure, to have shell access to all the affected systems and so on.
I guess I could manually copy the key to some well-known URL, maybe on the same server that hosts KC, and use that URL to automatically get the public key in my express deployments, and that would solve some of the problems. Still, I wonder if this is really needed, or if it's only my KC that lacks the public key reachable from a public URL, maybe for some bad configuration on my part.
@lucrus73 I am able to see my public key at https://[keycloak]/realms/[realm]
Thanks for your help, and let's go back to the original question of this thread: writing a migration guide.
@marcoBros suggested the best candidate to replace keycloak-nodejs-connect
would be express-openid-connect
.
Shortly after @coeing raised the stakes, suggesting you don't even need a replacement, as the backend already has all it needs in the token. You can just verify that and you're all set.
While @coeing suggestion looks brilliant, it does bring up a few more questions (at least to me): assuming it is the way to go, what keycloak-nodejs-connect
was written for in the first place? E.g. what its added value was back in the day? Maybe that value vanished with recent KC releases and that's exactly why it's now being deprecated? Or that is not the reason for deprecation as there are other problems that you could still solve easier with keycloak-nodejs-connect
, so those solutions now need a migration guide?
Or, rephrasing: why has keycloak-nodejs-connect
been deprecated?
@abstractj @jonkoops can you please confirm that solution by @coeing can be used safely?
80% people who use this library, use it only to verify roles.
I would very much appreciate code example how to do that with any library you suggested. Solution with only jwt
and public key from keycloak(by @coeing) also seems nice but would be better to get confirmation from authors of this library.
If her approach is not suitable, then can you give us code example how to use it with https://github.com/panva/node-openid-client if possible? Thanks in advance 🙏
80% people who use this library, use it only to verify roles
and what the remaining 20% use it for? Maybe that will shed some light on the reason why it was deprecated.
80% people who use this library, use it only to verify roles
and what the remaining 20% use it for? Maybe that will shed some light on the reason why it was deprecated.
What I can imagine to have used this library for: If you have an application with some custom UI to manage users and add them to groups, you could route those changes through your backend to Keycloak instead of directly changing it inside Keycloak. This would hide the implementation details (e.g. which groups will give which permissions) from the frontend.
Just my thoughts without having used the library myself :)
I proposed another alternative which I already use quite for some time in my app: https://github.com/keycloak/keycloak-nodejs-connect/issues/492
Hope it will be helpful for someone.
Btw, It will fetch public keys from keyacloak server automatically when previous one will become invalid, so there will be no need to put key manually in .env file every time, @lucrus73
Sure, but that requires to manually copy the public key into .env
@valerii15298 Thanks, I know, as @PaleHazy already suggested (I suppose you meant public keys, not private)
it seems there is a good replacement now, straight from Keycloak itself:
https://github.com/keycloak/keycloak/tree/main/js/libs/keycloak-admin-client
@lucrus73 no, it has different purpose, though you can use it to validate keycloak tokens
@valerii15298 You're right, but I mean you could use keycloak-admin-client to cover only that 20% left out from the @coeing solution, which I'm using and I can confirm it works wonders.
Assuming that 20% is what @coeing described in his comment, which in fact happens to be in my case, then @coeing solution plus keycloak-admin-client is all you need to cover 100% of the previous use cases for keycloak-nodejs-connect. So we could have a migration path.
But this is only my 2 cents, which I don't even need myself, because I'm already doing well using this solution.
The
openid-client
library is a likely recommendation for a low-level approach to the spec. For easier higher level integration we're thinking of recommendingexpress-openid-connect
.Feel free to try these out and let us know what your experience is.
I have been able to use openid-client for confidential client authentication via client credentials grant and resource management using the protection API without much issues.
Working with keycloak version 23.
The
openid-client
library is a likely recommendation for a low-level approach to the spec. For easier higher level integration we're thinking of recommendingexpress-openid-connect
. Feel free to try these out and let us know what your experience is.I have been able to use openid-client for confidential client authentication via client credentials grant and resource management using the protection API without much issues.
Working with keycloak version 23.
Can you please help us with some examples with how you achieved resource management using openid-client.
Once we have settled on a recommended alternative and covered all the edge cases and missing features we need to write a migration guide for users of the Node.js Connect adapter.