Using Token Exchange to refresh 3rd party IDP Access Token

I have locally running Keycloak 19 instance with --features=preview.
I’m specifically interested in using the Token Exchange (from internal token to external token).

www.keycloak org/docs/latest/securing_apps/#internal-token-to-external-token-exchange

My use case is that I want to use Google as a 3rd party Identity Provider and I want to be able to get my hands on the Google’s Access Token.

For the duration of one hour, as long as the original Google’s Access Token is valid, things work as I expect them to:
Request

curl --request POST \
  --url http://localhost/realms/master/protocol/openid-connect/token \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data client_id=account-console \
  --data grant_type=urn:ietf:params:oauth:grant-type:token-exchange \
  --data requested_token_type=urn:ietf:params:oauth:token-type:access_token \
  --data requested_issuer=google \
  --data subject_token=<Keycloak Access JWT>

Response

{
	"access_token": "<Google Access token>",
	"expires_in": 2935,
	"refresh_expires_in": 0,
	"token_type": "Bearer",
	"not-before-policy": 0,
	"scope": "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile openid",
	"issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
	"account-link-url": "http://localhost/realms/master/broker/google/link?nonce=a6644439-227c-4b0d-b9ce-cee395faa9e1&hash=MZY1V9I5_9uCEOACLWR6B1BRX6fATw0x3kcjFNq2JKM&client_id=account-console"
}

Actual behavior

However, after one hour, when the original Google’s Access Token expires, I get an error:
Response

{
	"error_description": "linked token is expired",
	"account-link-url": "http://localhost/realms/master/broker/google/link?nonce=36627052-fe42-42b7-825c-356cb0fc836b&hash=Fv4GkXuH1BQdcoB_4VnWHbSmTE7asHUMu1z0-Jl_iuY&client_id=account-console",
	"error": "token_expired"
}

Expected behavior

After an hour and original Access Token expiration, when calling the Token Exchange API, Keycloak uses Google’s Refresh Token that it has stored to get a new fresh Google Access Token which it then returns.

Is there away to get the expected behavior from Keycloak?

Thank you very much for any kind of help or hint. Maybe I’m just making a small mistake on the way which prevents Keycloak from doing this.

Other possibly related questions:

2 Likes

Hi,
did you managed to find any solution? I have the same problem.

Did you find a solution to this? I am also facing the same issue but with an Azure AD token.

Have the same issue too. I also try to eneable token exchange capabilities on Keycloak but the server always give me the expired access token.

Is there a way to force a token renew on external IDP?

Hello. Has anyone gotten anywhere with this? I’m stuck too with refreshing from another keycloak instance. If you turn off store tokens. it forces relink of all accounts on login.