Search code examples
oauth-2.0keycloak

Keycloak UMA workflow question: Why should the client ask for RPT token and not the resource server?


I have a keycloak authentication server, an angular front end and a spring resource server (using OAuth2 /UMA). At the moment, I sign in to the keycloak via the front end (angular, web page) and get an access token. When I need to access a resource I send a request to the resource server with my access token. If the resource server needs to make sure that the questioned resource is really accessable (e.g. missing rpt token), it will now create a ticket which it sends to the client. The client will send this ticket to the authentication server, gets an updated token (with rpt, of course only if allowed) and returns with that token to the resource server, finally getting back the resource (if the resource server is okay with it).

My question: As in my case, the basic authentication is upfront via angular web client, I would rather have the resource server talk directly to authentication server, if needed. It seems as less of a hassle. Or do I miss something important?

On a side note: I have the user authenticate to the front end, as this is an entry point to different resources (which may be present on different resource server).

Any help / thoughts appreciated.

From all what I read, the UMA flow suggests, that the resource server should give the ticket to the client (https://docs.kantarainitiative.org/uma/wg/rec-oauth-uma-grant-2.0.html#high-level-flow).

I feel, that this scenario differs from mine, as in my case, the client already signed in, whereas here, the initial client request to the resource server comes without authentication.

Update: One reason came to my mind: The client can of course store the token, so there is no need to request a new rpt token everytime if the rpt token is valid for a specific resource. Can the spring oauth server store that as well? Or is this bad practice?


Solution

  • Another reason might be that with this flow, it's up to the client to decide whether it wants to trigger an asynchronous authorization flow in case the user does not have access. This can be done in keycloak by passing the submit_request=true option when requesting the RPT.

    For more info see: https://www.keycloak.org/docs/latest/authorization_services/index.html#_service_authorization_aat

    Edit: I did some further research and it seems like the primary reason for the client having to request the RPT is the option for interactive claims gathering or claims pushing. In some cases the authorization server might not have all necessary information to conclude whether the user has access or not. Therefore further interaction between the client and authorization server is needed before an RPT can be issued (f.e. the user has to enter some additional information).

    https://wso2.com/library/article/2018/12/a-quick-guide-to-user-managed-access-2-0/

    Anyway in Keycloak there is also the option to skip this whole process and evaluate the user permissions directly from the resource server, using the access token attached to the request like this:

    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"
      --data "response_mode=decision"
    

    This will give you a result in the following format, indicating whether the user has the specified permissions or not.

    {
        'result': true
    }
    

    You can read more here: https://www.keycloak.org/docs/latest/authorization_services/index.html#_service_obtaining_permissions