top of page
Search

Keycloak Cross-Realm Token Exchange

  • alianah31
  • Mar 6
  • 2 min read

Goal: authenticate as a user in Realm A, and exchange that access token to impersonate a user in Realm B.


Prior art:


So - we're going to follow the Stack Overflow answer more or less verbatim to start. The instructions flip-flop the realm names, so for the rest of this post:

  • Realm A -> target realm (containing user to be impersonated)

  • Realm B -> source realm (containing user to do the impersonating)


Step 0 - Start Keycloak with features enabled

./bin/kc.sh ${START_CMD} \
  ... \
  --features="token-exchange,admin-fine-grained-authz" \
  ...

Step 1 - Create new Realms


Create Realm A (Target)
Create Realm A (Target)
Create Realm B (Source)
Create Realm B (Source)

Step 2 - Create realm-b-client

Note - in the SO answer, they actually create the IdP first, but this doesn't seem to be possible, as the IdP creation step requires a client ID/secret. So creating that here first.



ree
ree


ree

Grab the client secret for later

wfNaIERSgHHV6WHCKcTgxJXuKSbMhtpl

Step 3 - Create the IdP in Realm A


ree

ree

Step 4 - Create client in Realm A



ree
ree
ree

Step 5 - Configure Token Exchange Permissions


This is where instructions get a little wonky. The SO answer says "Go to the Permissions tab in realm A" - There isn't a realm-level permissions tab that I can see anywhere, so I'm assuming that this means permissions for the realm-a-client:


Enable fine-grained permissions:

ree

Note - "token-exchange" is already in the permission list, so no need to "enable" it (and in fact no way I see to disable it).


"Edit the Token Exchange Scope" - Opening up the token-exchange permission settings, scope is already filled out to be "token-exchange"... Not sure what else it should be?

ree

Add a client policy:

ree
ree
ree
ree

Step 6 - Create users in each realm


In source realm (realm B), create impersonator

ree
ree

In target realm (realm A), create impersonatee

ree
ree


Step 7 - Perform Token Exchange


Start by logging in the impersonator:

> service_token=$(curl -s \
  -X POST \
  'https://.../realms/realmB/protocol/openid-connect/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'client_id=realm-b-client' \
  -d 'client_secret=wfNaIERSgHHV6WHCKcTgxJXuKSbMhtpl' \
  -d 'username=impersonator' \
  -d 'password=ImpersonatorPassword' \
  -d 'grant_type=password' | jq -r .access_token)
> echo "${service_token}"
eyJ...gG7w

Now use that token to exchange for the impersonatee:

> curl -L 'https://.../realms/realmA/protocol/openid-connect/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
  -d "subject_token=${service_token}" \
  -d 'subject_token_type=urn:ietf:params:oauth:token-type:access_token' \
  -d 'client_id=realm-a-client' \
  -d 'client_secret=eYlm0uFYL9ruKMdRAOkN8SJa2NPdNrey' \
  -d 'subject_issuer=realm-b-idp' \
  -d 'audience=token_exchange' \
  -d 'scope=openid profile roles' \
  -d 'requested_subject=impersonatee'
{"error":"access_denied","error_description":"Client not allowed to exchange"}

So unfortunately - still missing some permissions somewhere...?



 
 
 

Comments


Drop Me a Line, Let Me Know What You Think

© 2035 by Train of Thoughts. Powered and secured by Wix

bottom of page