6

We are using KeyCloak Identity Brokering to federate authentication to an external IDP. The Identity Provider is of type OpenID Connect v1.0. Additionally, we are using OIDC Authorization Code Flow with PKCE.

We are successully able to retrieve the tokens from the external IDP based on the following documentation: https://www.keycloak.org/docs/latest/server_admin/#retrieving-external-idp-tokens

However, when the KeyCloak token is refreshed using "refresh_token" grant by the user-agent, the tokens from the external IDP are not. There is very little documentation available from KeyCloak on this topic.

Does anyone know how to refresh the tokens from the external IDP ?

Update: I have opened an issue with KeyCloak community https://github.com/keycloak/keycloak-community/issues/277

  • Did you find any solution? We experience the same issue. – Mario Eis Feb 24 '21 at 14:20
  • We haven't found a perfect solution yet. For the time being we are refreshing the tokens from the IDP, outside of KeyCloak. This however has some limitations as we depend on IDP to not revoke the original refresh token. – Ayondeep Datta Feb 26 '21 at 02:50
  • Thank you very much for your response! That's about the workaround I too had in mind. But for now I am still a bit reluctant to do that :) – Mario Eis Feb 26 '21 at 09:30
  • Let us know if you find a better solution :) – Ayondeep Datta Feb 27 '21 at 15:52
  • I had exactly the same issue (https://keycloak.discourse.group/t/is-it-possible-to-use-an-keycloak-accesstoken-to-get-access-to-the-microsoft-graph/6831/8) @AyondeepDatta : can you provide some information on the code you use now to manually refresh the external IDP token? – Stef Heyenrath Mar 03 '21 at 13:00
  • the link to https://github.com/keycloak/keycloak-community/issues/277 is dead – Sébastien Helbert Oct 29 '21 at 09:09
  • The solution suggested by @Hawk using the exchange token endpoint seems the way to go (see https://www.keycloak.org/docs/latest/securing_apps/#internal-token-to-external-token-exchange). I tested it and it works as expected but this is a preview feature. What is the purpose of the External IDP Token endpoint if it may return stale data (expires_in is not updated, acces_token may be expired, threre's no access_token creation time, ...) ? – Sébastien Helbert Oct 29 '21 at 09:14
  • 1
    I can't reach the KeyCloak issue that I opened on this topic either (https://github.com/keycloak/keycloak-community/issues/277). It seems like they took down their issues section from github. I had also created a topic in Keycloak discourse sometime ago, but I haven't heard back anything form their team (https://keycloak.discourse.group/t/keycloak-does-not-refresh-external-idp-token/11261). I am not sure what is the best way to reach out to KeyCloak team anymore. Seems like it is a more closed door affairs. – Ayondeep Datta Feb 07 '22 at 01:18

3 Answers3

2

Keycloak retains both the access token and refresh token from the upstream IdP. When you perform a token exchange it will refresh the tokens if the access token has expired but the refresh token has not, seen here: https://github.com/keycloak/keycloak/blob/master/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java#L186-L187

The long-and-short of it is you need to call the token exchange endpoint more often than the external refresh token expires. Depending on your implementation you can take advantage of this in a number of ways. For example, I've set my access token ttl shorter than the external IdP's refresh token ttl and I've got a confidential client that calls the token exchange endpoint every time it sees a new access token, it isn't the best possible solution but it's better than a sharp stick in the eye.

I don't know why the Keycloak developers don't just refresh any external token when you perform a token refresh of your Keycloak-minted token. They're smart people, so I'm sure there's a reason, but thus far I haven't been able to figure it out. I've been considering extending the existing OIDCIdentityProvider to do just that but I'd rather not open that can of worms until I understand what I'm getting into. If anyone has any insight I'd appreciate it.


micpap25
  • 728
  • 5
  • 21
Hawk
  • 31
  • 2
  • Thanks for suggesting a solution @Hawk. However, I am not sure if this solves the core problem here or may be I am missing something. The problem wasn't about getting the external IdP tokens (access & refresh), which works perfectly as described in the "Retrieving external IdP tokens" section in the Keycloak documentation. The problem is that the external IdP refresh tokens are not renewed when the OAuth2 refresh token grant is executed on the broker realm. – Ayondeep Datta Feb 07 '22 at 01:30
  • Take a look at the code linked above, when you perform an external token exchange keycloak will refresh the external access token if it has expired and the external refresh token has not. – Hawk Feb 08 '22 at 14:21
2

The solution proposed by @Hawk refers to a different API - Token Exchange - which can be used to retrieve (or even forge) tokens on KeyCloak. Among all different tokens you can exchange, you can retrieve tokens from configured Identity Providers, and is what we ended up using in the end.

Long story short, the "Retrieving external IDP tokens" functionality you are using will not refresh the token for you: if you plan to use it, you'll have to retrieve the refresh token and generate a new access token yourself, which is unfortunate as this would force you to have the client/secret ids of the Identity Provider on your application.

The Token Exchange API will instead refresh the token for you. You can easily retrieve the IP access token by issuing this request (the example uses python, you can obviously use any other language):

    response = requests.post(
        f"{ID_PROVIDER_HOST}/auth/realms/{REALM}/protocol/openid-connect/token",
        data={
            "client_id": CLIENT_ID,
            "client_secret": CLIENT_SECRET,
            "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
            "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
            "requested_issuer": IDENTITY_PROVIDER_ALIAS,
            "subject_token": access_token,
        },
    )

You need some configuration, though: first of all, Token Exchange is in "Technology Preview" as of current KeyCloak version (17), and is not enabled by default; refer to the KeyCloak documentation to see how to enable it.

Then, you'll need to enable your client to exchange IP tokens: from the administration panel of your realm:

  • select "Identity Providers" from the sidebar;
  • select the identity provider you want to retrieve the token from;
  • select the "Permissions" tab;
  • enable permissions, if not already enabled;
  • click on "token exchange"
  • in the "Apply Policy" table select "Create Policy" of type "Client"
  • give the policy a name, and select the client you want to be able to retrieve the access tokens.
StefanoP
  • 3,798
  • 2
  • 19
  • 26
  • getting error after if external token is expired Uncaught server error: java.lang.RuntimeException: com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'HTTP': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false') at [Source: (String)"HTTP Basic: Access denied. – Ritesh Khatri Mar 01 '23 at 12:06
0

Apologies for reviving a dead thread. Can I confirm that you are saying that the Token Exchange will automatically renew the token for us? Or do we need to call the token endpoint for this to occur? Or will it not renew at all?

  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/34578347) – Aaron Meese Jun 26 '23 at 17:29