maxime chevry
maxime chevry

Reputation: 73

Keycloak authentication: how can a external user get an token without exposing client secret

I have a query about how keycloak is supposed to be working with client without GUI access.

Basically I have:

This is kind of working already as I am able to log on the GUI, have the redirect, etc..

Even accessing the APIs works well, when I have access to a GUI: I log on my UI, follow the redirect and get my UI to display the token. The the human (to differentiate the user from an application), can use the token in any API client.

In this context the user never sees the client secret, which is instinctively the right way. (note that I am very opened to people telling me my instinct is wrong!)

What I am NOT able to do so far is to find the way a server application (without GUI) can get a valid token?

The authorization_endpoint, as far as I understand it, requires both the client id and the client secret) to get a token, which I would rather avoid: I don't think giving my client secret to all my "customers" is the proper way to do it.

Alternatively I could create an API on my client that woudl ask for user credential and ask for the token in its behalf, but that would expose the clients credentials to my application, which is against the whole concept!

I tried setting my client Access type as public, but when I use the API call below I also get a error:

POST /auth/realms/realmname/protocol/openid-connect/tokenAPI 
'grant_type=client_credentials'
'client_id=client_id'
'username=username'
'password=password'
{
    "error": "unauthorized_client",
    "error_description": "Public client not allowed to retrieve service account"
}

Would anyone know how this is supposed to be done ?

Thanks in advance.

Max

Upvotes: 6

Views: 12122

Answers (2)

beta-developper
beta-developper

Reputation: 1774

I just had the same problem some weeks ago

In my case, I have a backend API and a frontend application that the users can use. Eventually, I can't share the client_secret to the frontend application.

So here is my solution:

  1. On keycloak, create a client (ex front_end_client) with grant type public This client is going to be used by the frontend application to authenticate users using implicit flow (with PKCE will be more secure)

  2. On keycloak, create a second client (On the same REALM as the first client) with grant type confidential, this client is going to be used by the backend API

Now, this is how it works:

  1. Frontend app authenticate users and get the access token (Using the font_end_client)

  2. The frontend app sends this token for every request to the backend

  3. Backend app verify this token, and can retrieve permissions from it

Upvotes: 2

bsaverino
bsaverino

Reputation: 1285

(...) A server application (without GUI) can get a valid token... typically using the Client Credentials flow.

But we would define in this case a dedicated Client for your server (client?) application to authenticate against. The returned token (not bound to a specific user) will serve for authorizations on allowed applications (i.e. your classic GUI or API clients).

So, basically you should (in very short):

  • define a specific confidential Client in your Keycloak
  • add the desired applications (or other Clients) to the Client Scope(s). Those you want to authorize transitively from this Client.
  • authenticate against this Client with Client Credentials flow (given the token endpoint, client id, credentials, scope)
  • ensure that you are authenticating through TLS and that parameters are included in request body (and not in headers - for enhanced privacy)
  • further harden security of your Client(s)

When you do not want anymore this particular server (client?) application to access your applications, you can change the corresponding "authentication" Client's secret/credentials or simply delete it.


"I don't think giving my client secret to all my "customers" is the proper way to do it."

You are right and the proposed method above strictly avoids that. Each customer would have its own credentials.

EDIT

(adding more details)

By performing as above, you would end up with the following scheme:

                                   Flow         Keycloak Server
C/S app. or Customer X  <--- Client Creds --->  Auth. Client X
                         --- Access Token --->  Appl. Client    <-->  Appl. Server

C/S app. or Customer Y  <--- Client Creds --->  Auth. Client Y
                         --- Access Token --->  Appl. Client    <-->  Appl. Server

         Browser users  <--- Standard  ------>  Appl. Client    <-->  Appl. Server

Note: this is not a detailed flow chart. Arrows mostly show relationships here.

Finally, please note that the terminology may differ a little here, but the proposed method is basically the same that Google uses. So you may aswell take some inpiration from there:

Upvotes: 4

Related Questions