Token Exchange with Azure AD Access Token – subject_token validation failure

Hello everyone,

I’m currently working on configuring token exchange in Keycloak and I’m running into an issue I haven’t been able to resolve.
I’ve tested with versions 26.2.5, and despite multiple configuration attempts the exchange keeps failing when using an Azure AD v2.0 access_token as the subject_token.

Could you please help me understand what I might be missing, or confirm if this is a limitation/bug in the current Keycloak version? Any guidance or examples from those who have successfully integrated Azure AD access tokens with Keycloak token exchange would be greatly appreciated

Tested Keycloak versions: 26.2.5

Scenario

  • Trying to configure token-exchange between Keycloak and an external OIDC IdP (Azure AD).
  • Azure AD issues a v2.0 access_token (validated independently against the Azure JWKS using OpenSSL – signature and kid are correct).
  • Keycloak client token-exchange-test has Client authentication enabled, Authorization enabled, Standard Token Exchange enabled.
  • Token exchange request example:
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
subject_token_type=urn:ietf:params:oauth:token-type:access_token
requested_token_type=urn:ietf:params:oauth:token-type:access_token
audience=token-exchange-test
subject_token=<Azure access_token v2.0>

Expected behavior

Keycloak should accept the Azure AD access_token as subject_token and return a local access_token for the configured client.

Actual behavior

The request always fails with:

{
  "error": "invalid_request",
  "error_description": "Invalid token"
}

Keycloak logs (DEBUG/TRACE)

Failed to verify identity token: Key not found

Context about this error

  • Even when Validate Signatures is disabled in the IdP config or pods are restarted, the error persists.
  • The Azure token’s kid exists in the tenant’s JWKS and signature validation succeeds outside Keycloak.
  • From the log, it seems Keycloak tries to validate the subject_token as an ID Token issued by the local realm rather than an external access_token, which leads to the “Key not found” error.

Questions

  • In Keycloak 26.2.5, is it required to configure a Client Policy with External Token Exchange to allow access_tokens from external IdPs?
  • Has the validation logic for subject_token changed recently (i.e., does Keycloak only support ID Tokens by default)?
  • What is the supported way to enable token exchange using an external Azure AD access_token in 26.x?

If you are using the Standard token exchange, which is the new feature (v2), then only internal token exchange is possible. That’s also mentioned in the guide.
If you need external token exchange, read also the mentioned guide, as there is mentioned, that you have to enable the legacy token exchange feature and how external token exchange is done.
I’ve been using both approaches, both work, the legacy token exchange is hard to configure, but it works (or, at least it worked in the past, haven’t tested it since two years).

@dasniko, thanks for your reply!

Reviewing the documentation, I am already aware of the differences between the Standard Token Exchange (v2) and the Legacy Token Exchange.

Following the docs, we tried to configure external token exchange using the legacy approach with --features=preview,admin-fine-grained-authz enabled, and sending subject_issuer=azure in the request.

The problem we face is that in 26.2.5 there is no permission list that includes a token-exchange scope, neither under the Identity Provider configuration (no Permissions tab anymore) nor under the client’s Authorization settings. The only options available are the generic Authorization Services (Resources, Scopes, Policies), but nothing directly related to external token exchange.

I have tried:

  • Creating resources and policies manually under the token-exchange-test client.

However, the error persists and Keycloak still logs No resource object set up for target idp.

Questions:

  • In Keycloak 26.2.5, how are these IdP token exchange permissions supposed to be enabled/configured, given that the UI no longer provides a Permissions tab for Identity Providers?
  • Is there an official way to initialize the required resource objects and permissions for external token exchange in this version?
  • Or is external token exchange considered deprecated in 26.x and only internal (realm-to-realm or client-to-client) exchange is fully supported?

Any clarification on the correct way to configure these permissions in recent Keycloak versions would be very helpful. Thanks