I am trying to set up two Keycloaks (26.5) as identity broker and identity provider. So that I can get a token from the identity provider via the identity broker in M2M settings.
My approach is to use token-exchange and to send two requests (curl for testing) to the identity provider. The first is for a “local” token, and the second is to exchange the token from IdP.
I set up everything in the best possible way:
-
for IdP I created a client
I created a realm
I can get a token with client-credentials using curl.
-
for Identity Broker,
I started Keycloak with –features=token-exchange,admin-fine-grained-authz:v1
I created realm
I created a client, enabled authentication, service account, and standard token exchange
I configured the identity provider, enabled store tokens, used credentials for IdP client, enabled permissions, and added policy
In client settings, I enabled permissions, selected the policy created above
In the client’s service account, I linked the identity provider
I keep getting “identity provider is not linked” for the second request, “error”:“not_linked”.
It is basically what is described here: Configuring and using token exchange - Keycloak
My first question would be: Is this scenario still possible?
Does anyone have experience with this setup?
What could be the issue? I created the link to the provider manually; it is there.
Yes this scenario is possible.
Yes I did it some weeks ago. Not exactly with 26.5, but with 26.4.
Have you Created a client on the idp side, which is the client you are using for authentication with the configured identity provider ?
I found the Code, where ur Error is coming from: keycloak/server-spi-private/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java at main · keycloak/keycloak · GitHub
Hi. Thank you for confirming that what I am trying to achieve makes sense.
I will try to provide more details.
- I run both Keycloaks on localhost, from docker container, on the host network on different ports, so that they can see each other for simplicity. I used the parameters as mentioned above.
- I set up IdP Keycloak: 1) create a realm, 2) create a client in that realm (authentication enabled, standard flow + some others), 3) remember client secret.
- On IdentityBroker side, 1) I created a new realm (different name), 2) created a client (same name) in that realm (authentication and token-exchange flow enabled), 3) I created an identity provider (named oidc) and used client id and secret from the IdP. 4) Enabled permissions for IdP, and followed Configuring and using token exchange - Keycloak, 5) I went to the client I created in 2) to Service Account Roles, to service-account- user, and to Identity Provider Links, where I clicked ‘Link account’ and filled in IdP client name. I think this step should link IdentityBroker client to the IdP client. I should not be getting the error I mentioned above.
- Then I tested it
ACCESS_TOKEN=$(curl -s -X POST \
http://localhost:8181/realms/<broker>/protocol/openid-connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=<clientid>" \
-d "client_secret=<client secrer>" | jq -r '.access_token')
curl -X POST \
http://localhost:8181/realms/<broker>/protocol/openid-connect/token \
–data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
-d client_id=<clientid> \
-d client_secret=<client secrer> \
–data-urlencode "subject_token=${ACCESS_TOKEN}" \
-d subject_token_type=urn:ietf:params:oauth:token-type:access_token \
–data-urlencode "requested_token_type=urn:ietf:params:oauth:token-type:access_token" \
-d requested_issuer=oidc
I am getting
{"error_description":"identity provider is not linked","account-link-url":"http://localhost:8181/realms/<broker>/broker/oidc/link?nonce=582a884b-ee2c-40be-8cc3-f
9359be579e1&hash=aayIYXCToVKVWB0YQHX6vrqmTXbpitDbGsVzfaUWRS0&client_id=<clientif>","error":"not_linked"}
IdP log/output is empty. In my opinion, IdentityBroker is not even trying to connect to IdP.
On IdentityBroker output, I can see this:
2026-03-18 12:51:26,025 WARN [org.keycloak.events] (executor-thread-16) type=“TOKEN_EXCHANGE_ERROR”, realmId=“900985f7-4b2b-4395-ac07-c32a3f247afc”, realmName=“myrealm”, clientId=“client”, userId=“null”, ipAddress=“0:0:0:0:0:0:0:1”, error=“invalid_token”, reason=“requested_issuer is not linked”, auth_method=“token_exchange”, grant_type=“urn:ietf:params:oauth:grant
-type:token-exchange”, requested_issuer=“oidc”, client_auth_method=“client-secret”
userId=null looks suspicious(?)
Looks like your calling the wrong instance or have linked it wrong.
I will try to find a tutorial or an example online which you can reference.
I would be glad. Thanks.
Address localhost:8181 is the IdentityBroker, localhost:8180 is IdP, IdP address is used in IdentityBroker to register IdP.
Linking is done in clientId service account on IdentityBroker. It asks for two parameters User ID and username, if I remember correctly. I used clientId from IdP for both. I tried different combinations. Nothing worked. I also tried to set it up programmatically via Rest API.
here you are calling the same Keycloak twice. In the second call you need to call the keycloakninstance, which has the token exchange enabled and the idp.
This is very sophisticated: https://medium.com/@heshani.samarasekara/keycloak-cross-realm-token-exchange-9a6dc5667f2c
Hi. Thank you for the reference.
You are right, I am trying to call one of my two Keycloak instances twice (the problem I am trying to solve is that I cannot access the second one, only via token exchange through the first one). The first one is configured similarly to how it is done in the tutorial you mentioned. The difference is, I need M2M access. I would like to use Keycloak from within the application, not via browser and login forms (no redirection urls, etc., in my opinion).
The first Keycloak should be configured as “Identity Broker” with token-exchange enabled and with IdP pointing to the second one.
Then, from the application (or via curls), I will ask the first one, “give me a token (internal) providing these credentials” and then “exchange this token for a token from IdP (external) providing these credentials”. This is how I understand it (internal to external token exchange). I got far, but I hit the wall when I couldn’t link the client with IdP (or something).
I will try to look into the tutorial carefully. It seems to work only with a single Keycloak but two realms, not doing M2M.
I don’t think that will ever work with service accounts, as those are not brokered as they are internal to each instance . To do the exchange, you need a user that authenticated at least once successfully via a brokered login.
I’ve build this in January for a customer.
But on our OTC infrastructure. That was straight forward. Locally will be a little bit of a hassle, because internal and external address:port.