zak905 / keycloak-api-key-demo

Demonstration on how to add an API key authentication feature to keycloak
MIT License
110 stars 20 forks source link

Example regarding backend use #3

Open Threnklyn opened 3 years ago

Threnklyn commented 3 years ago

Hi Zakaria, thanks for this great example. I've read your blog post about the possibility to add API-Key functionality to keycloak. In your example the backend has to check the key. Is there any way to return a signed JWT from keycloak if the api key is valid? This would enable the usage of the same backend logic for oidc users and api users.

zak905 commented 3 years ago

Hi @Kuchenm0nster, Sorry for the late reply. I am not sure if it's possible to generate an authenticated user token from the api key endpoint. I will check about that. In the meanwhile, if you want to obtain a token from a single request, you can look into client credentials oauth grant. I am not sure about your use case, but this grant is designed for service to service communication, and you don't need user interaction (like authentication_code), you just need to configure it from the keycloak admin. Here is an example request:

curl --request POST 'http://localhost:8080/auth/realms/your-realm/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=the-client-id' \
--data-urlencode 'client_secret=secret' \
--data-urlencode 'scope=email' \
--data-urlencode 'grant_type=client_credentials'
zak905 commented 3 years ago

Hi @Kuchenm0nster, Sorry again for the late reply, I got distracted. I did some research. IMHO, it would not be a good practice (but it's possible) to generate an authentication token out of this api key endpoint because it would be in some way by-passing the security mechanisms set by OAuth2. Let's say we want to generate a token in the same way as keycloak does from our endpoint. Looking at the OAuth2 grants, we are left with either the password or client_credentials grants (authorization_code needs two steps, the first one involving user login and consent). For the password grant, you need to provide and to know the user password, which makes it a sensitive way of getting the authorized only used in highly trusted systems. Even if we know to which user belongs the api key, we cannot know the password because well, it's encrypted before storing. So if I would say the password grant is is also excluded, because you need to provide the password and the api key, which kills the whole concept why we are using an api key. Now we are left with the client_credentials grant. The client_credentials relies on the service account associated with the keycloak client. If we copy the code used to generate the (JWT) token in our endpoint, the generated token will not bear the user identity but rather the service account identity. This could be a problem, because all users will have the same kind of permissions / restrictions, and the same identity. If this is still ok, then you can take a look at the code used to generate a token using client credentials here: https://github.com/zak905/keycloak/blob/master/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java#L678

Threnklyn commented 3 years ago

Hi @zak905, thanks for your reply. We have decided against the usage of api keys. Maybe the Token Exchange might be suitable. The service account gets the impersonation role and can exchange its token for a token of a real user.

adityakuchekar commented 1 year ago

Hi @zak905 , Were you able to find out anything related to returning a signed JWT (access token) if the api key is valid?

zak905 commented 1 year ago

Hi @adityakuchekar,

returning a signed JWT is possible, but it can be considered as an anti pattern since the OAuth flows (that are developped to ensure security would be by-passed. I am quoting a comment from a similar question I answered on my personal blog (the article can be found here):

Technically, it should be possible to generate an access token (with some hassle) from the api key endpoint. You can find some implementation details in this Keycloak class: https://github.com/zak905/keycloak/blob/master/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java. However, I see this as anti-pattern. Keycloak relies on protocols such OAuth2 (and OpenID connect) to generate tokens. OAuth2 follows some well defined specifications aimed at enforcing security and integrity of the tokens. By generating a token from the api-key endpoint, we are kind of by passing all these mechanisms.

If you are still not convinced, and want to generate a token from the API key endpoint, all the utils to generate a token can be found in the TokenManager: https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java

adityakuchekar commented 1 year ago

thanks for the suggestion @zak905