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).
- App → Authent = token
- 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” 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
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.