← Back to search
#smart
iss parameter collision with RFC 9207
9 messages · View on Zulip →
D
Dion McMurtrie Mar 17, 2026, 10:53 AM
I recently noticed a parameter naming collision with SMART apps running against Keycloak 24 which implements RFC 9207. The problem SMART App Launch and RFC 9207 both use a query parameter called iss , but they mean completely different things: SMART App Launch (since ~2014): iss = the FHIR server base URL , passed in the launch URL. e.g. https://app/launch?iss=https://ehr/fhir&launch=xyz123 ( SMART App Launch spec ) RFC 9207 (March 2022): iss = the authorization server's issuer identifier , appended to the OAuth callback URL as a countermeasure against mix-up attacks. e.g. https://app/redirect?code=abc&state=xyz&iss=https://keycloak.example.com/realms/myrealm ( RFC 9207 , specifically Section 2 for the parameter definition and Section 2.4 for client validation requirements) Keycloak added RFC 9207 support in version 23.0.0 (November 2023), enabled by default. Since then, when the authorization server redirects back to the app's redirect_uri , it appends iss=<keycloak issuer URL> to the callback. This can break things in at least two ways - my experience was fhirclient.js (smart-on-fhir/client-js) picking up the Keycloak issuer URL in the redirect and mistake it for the FHIR server, but the extra iss parameter could cause redirect_uri mismatches at the token endpoint if the client doesn't strip it before constructing the token request. There's a relevant Keycloak issue keycloak/keycloak#25684 where users discovered the iss parameter was the root cause and the workaround was to disable it. Current workarounds Keycloak per-client toggle : In the Keycloak Admin Console → Clients → [your SMART client] → Advanced → OpenID Connect Compatibility Modes → enable "Exclude Issuer From Authentication Response". This suppresses the RFC 9207 iss on the callback. Works, but trades away a security feature. Strip iss client-side before calling ready() : In your redirect page, remove the iss param from the URL before the library processes it: const url = new URL ( window . location . href ); url . searchParams . delete ( "iss" ); window . history . replaceState ({}, "" , url . toString ()); FHIR . oauth2 . ready (). then ( client => { ... }); Both of these are band-aids. The first disables a legitimate security mechanism. The second requires every SMART app to add defensive code for something that should be handled at the library or spec level. The bigger question RFC 9207 adoption is only going to increase, it's required by FAPI 2.0 and is showing up in more authorization servers beyond Keycloak. It could be addressed at multiple levels Library fix (client-js) : The library could stop treating iss as meaningful on the callback page. During authorize() , the library reads iss from the launch URL to discover the FHIR server, then stores it in session state. By the time ready() runs on the redirect page, the FHIR server URL is already in session, there's no reason to look at iss in the URL again. Ignoring iss on the callback page would prevent the collision entirely. But still not make use of RFC 9207. Use the RFC 9207 iss for its intended purpose : Rather than just ignoring the iss on the callback, the library could actually validate it. During authorize() , the library already knows which authorization server it redirected the user to (discovered from .well-known/smart-configuration ). When the callback arrives with an RFC 9207 iss , the library could verify it matches the expected authorization server and reject the response if it doesn't. This gives SMART apps the mix-up attack protection that RFC 9207 was designed to provide, while still using the FHIR server URL from session storage for actual FHIR requests. This builds on #1, don't confuse the iss with the FHIR server, and additionally use it as a security check. Spec-level clarification (SMART App Launch) : The SMART spec currently defines iss as the FHIR server URL in launch URLs but says nothing about RFC 9207 using the same parameter name for a different purpose in callback URLs. A note acknowledging the collision and clarifying that iss on a callback is the authorization server issuer, not the FHIR server, would give library authors a clear mandate and put the problem on the radar for other implementers. Has anyone else run into this? I feel like I'm late to this issue since it was implemented in Keycloak so long ago.
Mikael Rinnetmäki Mar 19, 2026, 03:51 PM
Hi @Dion McMurtrie ! Thanks for the well written analysis! I remember runing into that (or a similar) issue some time back, but don't know the exact details nor how I resolved it. It was for some quick demo app, not for anythin in production.
Josh Mandel Mar 19, 2026, 06:38 PM
There are a few things going on here, thank you for the report and comments! One thing to say is it can be helpful to separate the "launch this app" url from the "receive an oauth callback" URL. The SMART iss is relevant at the former, and the RFC 9207 iss is relevant at the latter
Josh Mandel Mar 19, 2026, 06:38 PM
More generally we should think about whether we want to adopt protections like RFC 9207 explicitly in a future version of SMART.
Josh Mandel Mar 19, 2026, 06:43 PM
For the correct client library behavior, I think it would make sense to determine mode based on presence or absence of a "code" query parameter: if you have an issuer and no code you are in the launch mode; If you have a code you are in the callback mode.
D
Dion McMurtrie Mar 20, 2026, 12:30 AM
Thanks @Josh Mandel and @Mikael Rinnetmäki - really helpful. I'm not blocked by this - it’s straightforward to work around by disabling RFC 9207 in Keycloak on a per-client basis. That said, it raised the question of what the intended behaviour should be, and whether others have run into this. Following your suggestion @Josh Mandel , I’ve raised a PR to client-js to distinguish launch vs callback handling - https://github.com/smart-on-fhir/client-js/pull/205 I think it would be useful for the spec to clarify this and explicitly address how RFC 9207 should be handled. I’ve raised a change request and a draft PR based on my understanding of that approach Jira - https://jira.hl7.org/browse/FHIR-56141 Spec PR - https://github.com/HL7/smart-app-launch/pull/419 Hopefully this is useful, but I'm very happy for these to be refined, reworked, or discarded.
Josh Mandel Mar 20, 2026, 12:32 AM
Awesome thank you! I think your PR is very well done (adds clarity without incurring new implementation obligations at this stage)
Josh Mandel Mar 20, 2026, 12:33 AM
(We may even want to require support for this parameter from compliant servers in a future edition of the spec; after all, the security considerations that led to this RFC certainly do apply in the smart context.)
D
Dion McMurtrie Mar 20, 2026, 09:43 AM
Yes, I was shooting for clarity without any real change...but it might be good to consider requiring it at some point, that RFC exists for a reason. Anyway, glad it is helpful - I figured while I had it in my head I might as well...