Skip to content

THREESCALE-12102: Add token_exchange_enabled OIDC flow toggle#4313

Open
madnialihussain wants to merge 1 commit into
masterfrom
THREESCALE-12102-support-token-exchange
Open

THREESCALE-12102: Add token_exchange_enabled OIDC flow toggle#4313
madnialihussain wants to merge 1 commit into
masterfrom
THREESCALE-12102-support-token-exchange

Conversation

@madnialihussain

Copy link
Copy Markdown
Contributor

What this PR does / why we need it:

Adds token_exchange_enabled as a new OIDC flow toggle. This allows admins to enable/disable Standard Token Exchange (V2) on Keycloak clients via the 3scale UI and API, instead of configuring Keycloak manually.

Ticket requirements (THREESCALE-12102):

  1. Add native support in APIcast for validating OBO tokens: (Verified). APIcast validates OBO tokens out of the box since they are standard JWTs. Tested by obtaining an OBO token via Keycloak token exchange and sending it through APIcast, returned HTTP 200.

  2. Ensure compatibility with RHBK Standard Token Exchange (V2): This PR (Porta) + companion Zync PR. Adds the UI/API toggle in Porta that flows through Zync to set standard.token.exchange.enabled on the Keycloak client. Verified end-to-end: toggle ON → Keycloak shows true, toggle OFF → shows false.

  3. Provide configuration options to enforce policies based on both client and user claims: (Verified). The OBO token contains both client claims (azp, client_id) and user claims (sub, preferred_username, email, roles). APIcast extracts the client identity via jwt_claim_with_client_id (mapped to azp) for rate limiting, and existing policies like keycloak_role_check can enforce rules on user roles. Tested with an unknown client azp → APIcast returned HTTP 403.

Which issue(s) this PR fixes

https://redhat.atlassian.net/browse/THREESCALE-12102

Verification steps

  1. Navigate to a service's Integration > Settings > OpenID Connect > OIDC Authorization Flow
  2. Verify a "Token Exchange Flow" checkbox appears
  3. Toggle it on/off and save
  4. Verify via API: GET /admin/api/services/{id}/proxy/oidc_configuration.json returns token_exchange_enabled: true/false
  5. Run tests: bundle exec rails test test/models/oidc_configuration_test.rb

Note: End-to-end testing (Porta → Zync → Keycloak → APIcast) was done by temporarily cherry-picking commits from PR#4310 (OIDC sync token rotation). Will re-test after #4310 is merged.

@jlledom jlledom left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good to me! I modified the Jira ticket to add Apicast and Zync as components. Apicast accepts the JWT which includes user data but does nothing with it AFAIK, It just ignores the user data . I'm not sure what should apicast do with the user token, maybe just deliver it to the backend (maybe already does?), maybe extract it and add some extra header in the request to backend... IDK. But probably from porta side this the only thing we need.

@madnialihussain how did you figure out this was the appropriate thing to do? did anybody help you?

@madnialihussain

Copy link
Copy Markdown
Contributor Author

It looks good to me! I modified the Jira ticket to add Apicast and Zync as components. Apicast accepts the JWT which includes user data but does nothing with it AFAIK, It just ignores the user data . I'm not sure what should apicast do with the user token, maybe just deliver it to the backend (maybe already does?), maybe extract it and add some extra header in the request to backend... IDK. But probably from porta side this the only thing we need.

@madnialihussain how did you figure out this was the appropriate thing to do? did anybody help you?

Thanks @jlledom for the review and for adding the components. No, APIcast doesn't send user data to Apisonator. I verified this in the APIcast logs, the Apisonator call only contains service_id, service_token, usage[hits], and app_id=test-client. No user_id or any user data.

The JWT does get forwarded to the upstream service in the Authorization: Bearer header. I verified this using an echo server, which showed the full JWT in the request headers but no separate user identity headers like X-User-Id.

I went through the ticket, looked at how APIcast handles JWTs and how the existing OIDC toggles work with Zync and Keycloak ( took help with IBM Bob and Claude) then set up a local environment (Keycloak + APIcast + echo server) to test things out. The three requirement conclusions in the PR description are based on that.

@jlledom

jlledom commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Thanks @jlledom for the review and for adding the components. No, APIcast doesn't send user data to Apisonator. I verified this in the APIcast logs, the Apisonator call only contains service_id, service_token, usage[hits], and app_id=test-client. No user_id or any user data.

I'm not sure, but maybe some additional work in required in Apicast, @tkan145 WDYT?

I went through the ticket, looked at how APIcast handles JWTs and how the existing OIDC toggles work with Zync and Keycloak ( took help with IBM Bob and Claude) then set up a local environment (Keycloak + APIcast + echo server) to test things out. The three requirement conclusions in the PR description are based on that.

This PR was not an easy one. Good job!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants