Skip to content

THREESCALE-15279: Add an "audience" protocol mapper to Keycloak integration#597

Open
jlledom wants to merge 3 commits into
masterfrom
THREESCALE-15279-token-introspection
Open

THREESCALE-15279: Add an "audience" protocol mapper to Keycloak integration#597
jlledom wants to merge 3 commits into
masterfrom
THREESCALE-15279-token-introspection

Conversation

@jlledom

@jlledom jlledom commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Jira Issue:

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

Description:

As the issue describes, after a breaking change in a recent RHBK release, the token introspection feature stopped working. In order to fix it, we need to ensure the access token received from keycloak includes the client id in the aud field.

Keycloak provides a way to write on this field, which is installing a protocol mapper type oidc-audiende-mapper in all clients.

This PR modifies the Keycloak integration in Zync to add such mapper in the requests to the client registration service in Keycloak.

Verification steps:

  1. Ensure the server allows the oidc-audience-mapper for client registration
    • Keycloak: Realm Settings -> Client Registration -> Client Registration Policies
    • RHBK: Clients -> Client Registration
    • In both cases, add oidc-audience-mapper to the Allowed Protocol Mapper Types policy for both Anonymous and Authenticated clients
  2. Sync an application from porta. The fastest way is to regenerate the client secret.
  3. You should see the mapper in the server UI
    • Keycloak: Clients -> [client id] -> Mappers
    • RHBK: Clients -> [client id] -> Client Scopes -> [client id]-dedicated -> Mappers
  4. Get an access token
ACCESS_TOKEN=`curl   -d "client_id=[client_id]"   -d "client_secret=[client_secret]"   -d "grant_type=client_credentials"   "[endpoint]/auth/realms/[realm]/protocol/openid-connect/token" | jq -r '.access_token'`
  1. Get the introspection token
curl -X POST     [endpoint]/auth/realms/joan/protocol/openid-connect/token/introspect     -u "[client_id]:[client_secret]"     -d "token=$ACCESS_TOKEN"
  1. You should get a valid token. If you get {"active": false} then it's not working.

@jlledom jlledom self-assigned this Jul 1, 2026
@akostadinov-bot

Copy link
Copy Markdown

Compatibility & Correctness Review

The code change itself is clean and correct for the target use case (RHBK 26.6.2+). The oidc-audience-mapper type has been available since Keycloak 4.0 (2018), and the RESTAdapter for generic OIDC providers is untouched, so non-Keycloak services are not affected.

However, there are two operational risks worth discussing before merge:

1. "Allowed Protocol Mapper Types" policy will reject clients with 403

By default, Keycloak's Client Registration Policies do not whitelist oidc-audience-mapper. Any existing deployment that upgrades Zync without first adding oidc-audience-mapper to the "Allowed Protocol Mapper Types" policy (for both Anonymous and Authenticated clients) will get 403 Forbidden on every client create/update.

The PR description documents this as verification step 1, but it's actually a hard prerequisite — not a verification step. This should be surfaced prominently in release notes or a migration guide. Ideally, Zync would detect the 403 and log a clear message pointing at the policy configuration.

Ref: keycloak/keycloak#27558

2. Potential overwrite of existing protocol mappers

Previously, to_h omitted protocolMappers entirely, so Keycloak's Client Registration API left any existing mappers untouched on PUT. Now protocolMappers: [audience_mapper] is always sent, which — depending on Keycloak version — may replace all existing protocol mappers on the client with just this one. If an admin had manually added other mappers (e.g., group mappers, custom claim mappers), they could be wiped on the next Zync sync.

Worth verifying this behavior against the target Keycloak version, or consider reading the existing client's mappers and merging.

Test coverage gaps

  • No stubs updated for the create_client (POST) path — to_h is shared, so create requests also now include the mapper. If there are WebMock stubs matching POST bodies, they may silently not match.
  • No test for the 403 scenario when the mapper type is not whitelisted — this is the most likely failure mode in production.

Suggestion

Consider making the mapper configurable via Rails.application.config.x.keycloak (same pattern as self.attributes), so deployments on older Keycloak that don't need it can skip the policy prerequisite.

@jlledom

jlledom commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Hi bot that has nothing to do with @akostadinov.

1. "Allowed Protocol Mapper Types" policy will reject clients with 403

By default, Keycloak's Client Registration Policies do not whitelist oidc-audience-mapper. Any existing deployment that upgrades Zync without first adding oidc-audience-mapper to the "Allowed Protocol Mapper Types" policy (for both Anonymous and Authenticated clients) will get 403 Forbidden on every client create/update.

This is true. But the whole Jira issue is about adding this audience mapping. Right now, preparing an RHBK or Keycloak instance to be integrated with zync is a more complicated process, it requires creating a client there with the proper scopes and permissions to manage other clients in the realm. The users can do this because it's probably documented in some of our guides, the only thing we need is to tell Docs people to add a new step in that manual to add the audience mapper to the whitelist. And of course write some release notes.

2. Potential overwrite of existing protocol mappers

Previously, to_h omitted protocolMappers entirely, so Keycloak's Client Registration API left any existing mappers untouched on PUT. Now protocolMappers: [audience_mapper] is always sent, which — depending on Keycloak version — may replace all existing protocol mappers on the client with just this one. If an admin had manually added other mappers (e.g., group mappers, custom claim mappers), they could be wiped on the next Zync sync.

This is also true, but it's true also in master. Zync always completely replaces the whole client configuration on each event, so if somehow a client in RHBK happens to have a mapper, the current code in master will also remove that mapper in the next event. Clients are a resource completely belonging to zync and managed by zync, nobody should touch them manually.

Test coverage gaps

* No stubs updated for the `create_client` (POST) path — `to_h` is shared, so create requests also now include the mapper. If there are WebMock stubs matching POST bodies, they may silently not match.

I added such test: ddf7f91

* No test for the 403 scenario when the mapper type is not whitelisted — this is the most likely failure mode in production.

I don't think we need a test for this because we don't do anything special in this scenario.

@akostadinov

Copy link
Copy Markdown
Contributor

This is true. But the whole Jira issue is about adding this audience mapping. Right now, preparing an RHBK or Keycloak instance to be integrated with zync is a more complicated process, it requires creating a client there with the proper scopes and permissions to manage other clients in the realm. The users can do this because it's probably documented in some of our guides, the only thing we need is to tell Docs people to add a new step in that manual to add the audience mapper to the whitelist. And of course write some release notes.

I think that the bot was referring to the fact that if one upgrades 3scale but does not update RHBK, they will need to execute a manual step or the integration will break. And these manual upgrade steps are often missed. The concern is not new installations.

So is your suggestion to rely on release/upgrade notes?

This is also true, but it's true also in master. Zync always completely replaces the whole client configuration on each event ...

Have you verified that? Because the poor bot thought it didn't override default mappers on PUT previously.

... Clients are a resource completely belonging to zync and managed by zync, nobody should touch them manually.

I can't follow how overriding default mappers relates to touching clients manually.

@jlledom

jlledom commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

This is true. But the whole Jira issue is about adding this audience mapping. Right now, preparing an RHBK or Keycloak instance to be integrated with zync is a more complicated process, it requires creating a client there with the proper scopes and permissions to manage other clients in the realm. The users can do this because it's probably documented in some of our guides, the only thing we need is to tell Docs people to add a new step in that manual to add the audience mapper to the whitelist. And of course write some release notes.

I think that the bot was referring to the fact that if one upgrades 3scale but does not update RHBK, they will need to execute a manual step or the integration will break. And these manual upgrade steps are often missed. The concern is not new installations.

Yeah that's true.

So is your suggestion to rely on release/upgrade notes?

Do you have any other idea? either for new installations or for upgrades, they have guides and manuals, right?

This is also true, but it's true also in master. Zync always completely replaces the whole client configuration on each event ...

Have you verified that? Because the poor bot thought it didn't override default mappers on PUT previously.

Yes

... Clients are a resource completely belonging to zync and managed by zync, nobody should touch them manually.

I can't follow how overriding default mappers relates to touching clients manually.

Because a mapper is attached to a client, and clients are managed entirely by Zync. Zync doesn't add any mapper before this PR, so the only way for a client to have a mapper is if somebody actually went to the RHBK admin console, looked for the client and added the mapper to it manually. In that case, the next push from zync would remove it, also in current master

@akostadinov

Copy link
Copy Markdown
Contributor

Sounds good then. We just need to be very loud in release notes about upgrade manual steps.

akostadinov
akostadinov previously approved these changes Jul 9, 2026

@akostadinov akostadinov 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.

Looks good. I would consider the ability to turn this off though for customers on older versions and semi-compatible versions. Just to be sure. But only consider, leaving it on your judgement whether this will provide possible value or will only be unnecessary cruft.

@jlledom

jlledom commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

@akostadinov I tried to satisfy you and your bot: 1dca454

Now you can opt-out by setting ZYNC_CLIENT_AUDIENCE_MAPPER_DISABLED=1

@akostadinov

Copy link
Copy Markdown
Contributor

If we upgrade SaaS without ability to turn this on/off for individual accounts, then many SaaS customers will break. And it turned out very hard to get hold on customers to update their configs. So I think as it presently is implemented, it appears to me that we will have troubles with SaaS.

jlledom added 3 commits July 16, 2026 14:56
Add the ZYNC_CLIENT_AUDIENCE_MAPPER_DISABLED environment variable and
document the RHBK admin prerequisite: the oidc-audience-mapper type
must be added to Allowed Protocol Mapper Types in Client Registration
Policies before enabling the mapper. The kill switch allows operators
to disable the mapper instance-wide if needed.

Assisted-by: Claude Code
Add an oidc-audience-mapper protocol mapper to the Keycloak client
registration payload when audience_mapper_client_id is provided.
RHBK 26.6.2+ rejects token introspection when the calling client is
not listed in the token's aud claim. Porta will send the introspection-
calling client's ID as audience_mapper_client_id; Zync sets that as
included.client.audience in the mapper. A global kill switch
(client_audience_mapper_disabled) allows disabling it instance-wide.

Assisted-by: Claude Code
Update service and integration tests to verify the audience mapper
appears in Keycloak API requests when audience_mapper_client_id is
present in the entry data. Adds assert_requested assertions that were
missing, and updates Keycloak request body stubs to include the
protocolMappers field.

Assisted-by: Claude Code
@jlledom jlledom force-pushed the THREESCALE-15279-token-introspection branch from 13e7bcc to 0764f7a Compare July 16, 2026 12:58
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