oauth-2.0keycloak

Internal to Internal Token exchange with public client


I have a public client app from which I obtained the access token of a user via standard flow. I now want to obtain a token for the confidential client bridge of the same user (sub = same user ID).

I tried following https://www.keycloak.org/securing-apps/token-exchange#_internal_internal_making_request but it's sadly very ambiguously worded in some places.

My current request always gives me Invalid token.

The request:

curl --location 'https://example.com/keycloak/realms/test/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=<app token>' \
--data-urlencode 'requested_token_type=urn:ietf:params:oauth:token-type:access_token' \
--data-urlencode 'audience=bridge' \
--data-urlencode 'client_id=app'

Since it's a public client, there is no client secret. The manual only says that public clients are not allowed to perform token exchanges using tokens from other clients but the token is from the client app itself or is there a comma missing and it means a public client cannot exchange for other clients using a token in general?

My goal is just to trade down to a token with less permissions. But if the public client can only trade for other tokens of itself, how do I strip permissions from the resulting token?

Edit: I also added the bridge client to the audience field of the app user token, but sill no luck.


Solution

  • Usually in token exchange the main goal is one of the following and the token exchange request should include a scope parameter that represents something like a business area.

    The client must be authorized to:

    Most commonly, token exchange is done by backend conponents, like an API gateway or an API. Before calling the upstream they replace the original token in the HTTP authorization header with the exchanged token. Therefore, this type of backend component must be registered as an OAuth client with the token exchange capability and scopes.

    In your case I think an approach of the following kind, where you rule out causes one by one will help you understand Keycloak specific logic: