NumeroUno
NumeroUno

Reputation: 1160

Keycloak public client and authorization

We are using keycloak-adapter with Jetty for authentication and authorization using Keycloak. As per Keycloak doc for OIDC Auth flow:

Another important aspect of this flow is the concept of a public vs. a confidential client. Confidential clients are required to provide a client secret when they exchange the temporary codes for tokens. Public clients are not required to provide this client secret. Public clients are perfectly fine so long as HTTPS is strictly enforced and you are very strict about what redirect URIs are registered for the client.

HTML5/JavaScript clients always have to be public clients because there is no way to transmit the client secret to them in a secure manner.

We have webapps which connect to Jetty and use auth. So, we have created a public client and it works awesome for webapp/REST authentication.
The problem is as soon as we enable authorization, client type gets converted to Confidential from Public and it does not allow the reset it as Public. Now, we are in soup. We cannot have public clients due to authorization and we cannot connect webapps to confidential client.
This seems to be contradictory to us. Any idea why client needs to be confidential for authorization? Any help on this how can we overcome this issue?
Thanks.

Upvotes: 32

Views: 38589

Answers (4)

w08r
w08r

Reputation: 1814

Any idea why client needs to be confidential for authorization

The client needs to authenticate with keycloak in order to make full use of the protection api, to manage resources, and to create pat tokens.

Web applications should have their own client, with authentication disabled, which use the correct auth flow for SPAs (Auth code flow with PKCE).

The access token issued to the front end client can in fact be used with a different backend client representing the auth server. An example request is documented in the (albeit terse) keycloak documentation here.

curl -X POST \
  http://${host}:${port}/realms/${realm}/protocol/openid-connect/token \
  -H "Authorization: Bearer ${access_token}" \
  --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
  --data "audience={resource_server_client_id}" \
  --data "permission=Resource A#Scope A" \
  --data "permission=Resource B#Scope B"

The above example shows use of the access token (which may have the frontend client for azp) and the backend client id passed as the audience. This gets around the error mentioned above in the comments following @NumeroUno's answer:

Client application [public-client] is not registered as a resource server. 

Upvotes: 3

NumeroUno
NumeroUno

Reputation: 1160

After much deliberation, we found that authorisation is not required to be enabled on public client really when you connect to it. When any request come to public client, it only does the authentication part. Authorization part is done when actual request lands on the resource server (in our case, Jetty) using the confidential client (as Jetty has knowledge of confidential client configured in it).

Upvotes: 2

Arnold Obdeijn
Arnold Obdeijn

Reputation: 176

I think you are referring to the "Authorization Enabled" switch in the admin console of Keycloak, when creating a client. If you go over the question mark next to the label, you'll see the hint "Enable/Disable fine grained authorization support for a client.

Create client in Keycloak admin console (v 6.0.1)

This is meant for when you create a client for a backend application that serves as a resource server. In that case, the client will be confidential.

If you want to create a client for a frontend app, to authenticate a user and obtain an JWT, then you don't need this.

See also: https://www.keycloak.org/docs/latest/authorization_services/index.html

Upvotes: 2

maslick
maslick

Reputation: 3360

As far as I understood, you have your frontend and backend applications separated. If your frontend is a static web-app and not being served by the same backend application (server), and your backend is a simple REST API - then you would have two Keycloak clients configured:

  • public client for the frontend app. It would be responsible for acquiring JWT tokens.
  • bearer-only client, which would be attached to your backend application.

To enable authorization you would create roles (either realm or client scoped, start on the realm level as it's easier to comprehend). Every user would then be assigned a role/s in the Keycloak admin UI. Based on this you should configure your keycloak adapter configuration (on the backend).

All things considered, in order to talk to your REST API, you would attach a JWT token to each HTTP request in the Authorization header. Depending on your frontend framework, you can use either of these:

P.S. For debugging I have just written a CLI tool called brauzie that would help you fetch and analyse your JWT tokens (scopes, roles, etc.). It could be used for both public and confidential clients. You could as well use Postman and https://jwt.io

HTH :)

Upvotes: 32

Related Questions