keycloaktoken-exchange

Keycloak reauthenticate an Authenticated user with a different client


If I have a user that has authenticated with keycloak with public client C1 under realm R is there an endpoint I can hit in keycloak that will generate a new access token for a different public client C2 under the same realm R?

[Update #1] I tried using the refresh token to obtain a new access token for C2 client but I get the following error:

Invalid refresh token. Token client and authorized client don't match

[Update #2] So, the above gave me the idea of trying to use the exchange token grant type and I have it working now.

curl --request POST \
  'https://myhost.com.au/auth/realms/<my realm>/protocol/openid-connect/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
  --data-urlencode 'subject_token=<c1 access token>' \
  --data-urlencode 'subject_token_type=urn:ietf:params:oauth:token-type:access_token' \
  --data-urlencode 'requested_token_type=urn:ietf:params:oauth:token-type:refresh_token' \
  --data-urlencode 'client_id=<c2 client id>'

Solution

  • Your question makes sense. Unfortunately the role scope mapping documentation is elusive about how to generate a new access token when switching to a different client.

    There is an Oauth2 RFC about token exchange. As of Keycloak 11.0.2 token exchange is documented as a technology preview and has to be enabled with -Dkeycloak.profile.feature.token_exchange=enabled

    You can exchange tokens this way (actually taken from the question):

    Method: POST
    URL: https://<keycloak.host>/auth/realms/myrealm/protocol/openid-connect/token
    Body type: x-www-form-urlencoded
    Form fields:    
    . grant_type: urn:ietf:params:oauth:grant-type:token-exchange
    . subject_token: <C1-access-token> 
    . subject_token_type: urn:ietf:params:oauth:token-type:access_token
    . requested_token_type=urn:ietf:params:oauth:token-type:refresh_token
    . client_id: <C2-client-id>
    

    Here is some context from the "role scope mapping" documentation intended for other readers.

    When an OIDC access token or SAML assertion is created, all the user role mappings of the user are, by default, added as claims within the token or assertion. [...] access tokens are digitally signed and can actually be re-used by the application to invoke on other remotely secured REST services. This means that if an application gets compromised or there is a rogue client registered with the realm, attackers can get access tokens that have a broad range of permissions and your whole network is compromised. This is where role scope mappings becomes important.

    Role Scope Mappings is a way to limit the roles that get declared inside an access token. When a client requests that a user be authenticated, the access token they receive back will only contain the role mappings you’ve explicitly specified for the client’s scope.

    [...] To change this default behavior, you must explicitly turn off the Full Scope Allowed switch and declare the specific roles you want in each individual client. Alternatively, you can also use client scopes to define the same role scope mappings for a whole set of clients.