Obtain RPT without having to invoke Keycloak API twice

I’m implementing authorization in Keycloak, so I’ve set up resources, scopes, policies etc. and now I was just checking how this is reflected in the user access tokens.

I see from the docs that the RPT token contains the permission claims that I need
https://www.keycloak.org/docs/latest/authorization_services/#_service_rpt_overview

But this RPT can be obtained only once a user obtains an access token first. So, first step is to get the access token e.g.

curl -s --data "grant_type=password&client_id=${client}&client_secret=${secret}&username=${user}&password=${pass}" ${keycloak-url}/realms/${realm}/protocol/openid-connect/token`

and then e.g.

curl -s -H "Authorization: Bearer ${access-token}" --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket&client_id=${client}&audience=${client}" ${keycloak-url}/realms/${realm}/protocol/openid-connect/token

So, we get the RPT with the permission claims e.g.

...
  "authorization": {
      "permissions": [
        {
          "resource_set_id": "d2fe9843-6462-4bfc-baba-b5787bb6e0e7",
          "resource_set_name": "Hello World Resource"
        }
      ]
  },
...

Is there a way to provide the authorization claims like permissions etc. right away in the access token, without having to invoke Keycloak’s API twice?

1 Like

in your second request you get all available resources user having access to in the client, not just to the requested one. Is it required in your system? Typically a flow is like this: user authenticate in the system (login). Once user request a protected resource for the very first time, resource server issue a ticket for this resource, and you request RPT for just that resource using the ticket issued. Perhaps it means even more, 3 requests to Keycloak per protected resource. However once resource is requested, user can use this RPT for the next few minutes - as defined in the token life time policy , more to say you can develop a code to renew it with the RPT refresh token, means user may request for the protected resource only for the first time it is requested, and until logout, he can use RPT token instead. RPT token also supports incremental mode, means you can add to this existing token new resources . However in your approach you get entire list of the resources granted (it may take some time) and after that you can use this RPT for any resources and renew it before expiration . But no, i do not think you can make it less than in two requests to keycloak. One for authentication second is for authorization.

Hi, I’m also interested in this.

This is what I would call Speculative evaluation. Let me explain…

The two invocations that you mention are not supposed to be by the same party.

The first one is authentication by the client app: it provides authent data (here, username + passwd) and gets a token from the authent service. This token can be used by the client app to access any service, provided the audience is ok, date is ok etc. The client does not know how any data or calls are protected, it just uses a token as a black box.

The service called, the resource server, acts as a policy enforcement point (PEP). It gets a token, validates it, and then uses it to enforce policies, refusing or granting access to this or that resource that it controls.
For this it needs to evaluate policies. That’s not its job, it’s the job of a Policy Decision Point (PDP), so it does the second call, to get permissions from the PDP. Here the PDP is Keycloak. The PEP calls it, saying hey I want to know if I can grant access to these particular resources with these particular claims (the JWT). Keycloak evaluates the policies against all this, acting as PDP, and returns the permissions in an RPT (which may be as simple as yes/no, by the way, it doesn’t need to be a JWT or even a list of resources).
(note that the PEP could simply look inside the JWT and check the claims instead of permissions, but that means you can’t manage policies any more, a whole different discussion)

So first comment here: the 2 calls are to 2 different functions of Keycloak, that could actually be served by 2 completely different servers, or even products (Auth0, OPA, etc), Authent and PDP. Also, the 2 calls are from 2 different actors, the app (or client) and the PEP (or resource server).

  1. App → Authent = token
  2. PEP → PDP = RPT (permissions)

So it makes complete sense that they are different.

Important comment about separation of concerns: Even if the app thinks it knows which resources it’s getting, there’s no reason those would be the same “resources” known by the resource server and the policies.
For example, the app could get resource “name, zip code”, but the policies could know about “private data, public data”, and it would be up to the resource server to transform the request for name and zip code to the appropriate metadata, and use those to call Keycloak (PDP), because that’s what the policies know about (just some metadata, not the millions of actual data). The resource server could also decide that, to get the zip code, it needs access to a city directory, and this could be another resource for which it checks access rights from the policies. The app could also ask for some analytical data, and the resource server would be the only one to know what primary data is needed, and depending on that particular generation of analysis the resources to be accessed may change for the same analysis call.
It could also call another service with the same token (provided the audience is ok) and the other service would require other resources and other policies.
So in the general model, the app actually doesn’t know what “resources” it’s trying to access. It’s calling a resource server to get some result.

So it makes sense to have 2 calls. However, why not have only one call?
One call can be an optimisation. The rationale is: I’m ready to lose whatever separation of concerns, isolation, measure of precision, because for my system the 2 calls are going to be really costly, whatever the reason.
(of course always remember “premature optimisation is the root of all evil” :wink: so that kind of decision should not be made lightly)

In this case we want the app to get a JWT, but one that includes permissions (so, a RPT). Permissions for what resources? Heck, no one knows, see above everything that the resource server could actually decide… so whatever seems the most reasonable (remember, we’re optimising). For example all of them, or the most common, or the most commonly used by the main services…
And that’s why I call it “speculative evaluation”. The app has no idea what policy evaluations it’s going to trigger and what resources the PEP will need to access in the end. So whatever permissions the app gets in its token are speculations on what will most probably be needed.
(and if the resource server doesn’t find the permissions it’s looking for in the RPT, it can always call the PDP for another RPT)

To conclude, that’s why I’m following this question. The answer is interesting, because if it’s not possible, then this optimisation is not possible. I’m interested to know that.

PS: I guess it also makes sense if app = PEP. Meaning that the app authenticates, then actually wants to know if it can allow access to its own resources. That’s actually a special case of a resource server, it’s a resource server that accepts no token in the incoming calls, and is ready to ensure authentication to get the token. (in OAuth, normally a resource server gets a token as input and does not ensure authent)
I guess if you are there, then all of the above will appear uselessly complicated :smiley:
Well at least it will serve to explain why things are what they are!

PPS: a not-so-neat trick to solve this is to custom-code your JWT mapper to include claims that reflect permissions, but of course that doesn’t really answer the question because in that case you are ignoring all the policy model of Keycloak, with its resources, scopes etc.

PPPS: the API to get a RPT used to not even be the same as to get a token, by the way. Check out Upgrading Guide (keycloak.org)

Entitlement API was removed

With the introduction of UMA 2.0, we decided to leverage the token endpoint and UMA grant type to allow obtaining RPTs from Keycloak and avoid having different APIs. The functionality provided by the Entitlement API was kept the same and is still possible to obtain permissions for a set of one or more resources and scopes or all permissions from the server in case no resource or scope is provided. See Authorization Services Guide for details.

1 Like

Focusing on the APIs now…

A short answer is to your question is no because grant_type has to be password to get the authent token, and urn:ietf:params:oauth:grant-type:uma-ticket to get permissions. Can’t be both. :slight_smile:

Let’s look at why that is…

Note that urn:ietf:params:oauth:grant-type:uma-ticket, as its names indicates, is a standard grant type. It is defined here: User-Managed Access (UMA) 2.0 Grant for OAuth 2.0 Authorization (kantarainitiative.org). It’s part of OAuth.
So Keycloak, as OAuth implementation, has to comply with that.
(same for urn:ietf:params:oauth:grant-type:token-exchange by the way, except that Keycloak is still lagging behind on this one)

password, on the other hand… let’s say it is not standard. Well, not in the same way.

Check out OAuth 2.0 Password Grant Type and the authoritative source draft-ietf-oauth-security-topics-13

The resource owner password credentials grant MUST NOT be used.

So… I guess this means it’s used only in prototyping and using CLI to get a token.
What should be done: do not use grant_type=password, unless you are prototyping. Instead, your app should redirect to the authenticator, and not bother about how it does its authentication. If it still interests you, what Keycloak actually does is to use a different API, POST [...]/login-actions/authenticate, with name and password in the payload, not in the URL (much more secure and what most authenticators do)

This doesn’t really solve your question, BTW, it changes the question to:

  • is it possible to configure a UI client, using redirection to authenticate, so that it returns a RPT?

(I removed all mention of the “password” grant type)
Here we are really getting away from the normal flow. We would have to consider an implicit flow and get an RPT instead of a JWT.

I’m stopping here. My conclusion is that the original question is trying to fit a square peg into a round hole. Or using a hammer to put in a screw. It may be feasible, but more probably a waste of time leading to a bad result. :slight_smile:

Of course I’m always happy to be proven false.

PS: about standard or non standard grants, check out OAuth Parameters (iana.org)
Obviously the parameter “password” was never considered at the same level as the others. Either because when it was proposed the IANA stuff was not yet started, or more probably because it was not supposed to be a “real” parameter, just a placeholder until everyone used oauth properly, as explained here: What is the OAuth 2.0 Password Grant Type? | Okta Developer
That’s what I like about security, the rabbit holes :smiley:

2 Likes