Token exchange returns empty response for internal token to internal token exchange

Hi all,

Hoping a couple of eyes on this will help me solve it. I haven’t made much use of the preview token exchange feature, and I am trying to set up an example for Internal token to internal token exchange as described in the documentation.

Here’s the Keycloak setup:

  1. I made two Clients, test and target, both public clients with the same setup
  2. In the target Client, I enabled fine grained permissions
  3. In the realm-management Client, Authorization->Policies tab, I made a new Client policy called target-client-exchange

    with the configuration that included the test client
  4. Back in the target Client, Permissions tab, I configured the token-exchange permission with the policy I created in #3

And here is how I try to use it:

  var keycloak = Keycloak(); //this reads the client configuration for the `test` client
  keycloak.init({
    onLoad: 'login-required'
  }).then(function(authenticated) {
    tokenExchange();
  }).catch(function() {
    console.log('failed to initialize');
  });

  function tokenExchange() {                                                                             
    const url = keycloak.endpoints.token();                                                              
    var details = {
      'client_id': keycloak.clientId,
      'grant_type': 'urn:ietf:params:oauth:grant-type:token-exchange',
      'subject_issuer': keycloak.tokenParsed.iss,
      'subject_token': keycloak.token,
      'subject_token_type': 'urn:ietf:params:oauth:token-type:access_token',
      'requested_token_type': 'urn:ietf:params:oauth:token-type:refresh_token',
      'audience': 'target'
    };

    var formBody = [];
    for (var property in details) {
      var encodedKey = encodeURIComponent(property);
      var encodedValue = encodeURIComponent(details[property]);
      formBody.push(encodedKey + "=" + encodedValue);
    }
    formBody = formBody.join("&");

    fetch(url, {
      method: 'POST',
      mode: 'cors',
      cache: 'no-cache',
      credentials: 'same-origin',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      redirect: 'follow',
      referrerPolicy: 'no-referrer',
      body: formBody
    })
      .then((response) => console.log(response))
      .then((data) => console.log(data));
  }

After logging in, the tokenExchange() function runs, returns a 200, but there is nothing in the response. No errors in the Keycloak logs either. However, there is an event that indicates a successful token exchange happened

Any ideas on how I can get a token? What am I doing wrong?

And in the Sessions section, it thinks the user has a session in both test and target clients.