Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend OAuth2 Flow Broken, the "iss" Claim is Hard-Coded to the Keycloak URL #19953

Open
2 tasks done
cmiles74 opened this issue Apr 25, 2023 · 7 comments
Open
2 tasks done
Labels
area/oidc Indicates an issue on OIDC area kind/feature Categorizes a PR related to a new feature status/triage team/core-clients

Comments

@cmiles74
Copy link
Contributor

Before reporting an issue

  • I have searched existing issues
  • I have reproduced the issue with the latest release

Area

oidc

Describe the bug

Keycloak contains a hard-coded rule that will not let the "iss" claim be set to a custom value in an "access token".

Version

20.0.5

Expected behavior

This can be demonstrated by adding a hard-coded claim to a client scope, when you attempt to fetch an access token for that client an error will be written to the log file. If we had a Keycloak instance configured with such a client we might issue the following request:

curl https://my-keycloak-instance/auth/realms/myrealm/protocol/openid-connect/token \
  -H 'Cache-Control: nocache' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=client_credentials&client_id=CLIENT_ID&client_secret=SECRET_GOES_HERE'

I would expect the "iss" value in the token to be the values specified in the hard-coded claim.

Actual behavior

Instead the following message would appears in the log file...

Claim "iss" is non-modifiable in IDToken. Ignoring the assignment for mapper 'hardcoded-iss-mapper'.

...And the returned JWT token would have the URL for the Keycloak instance in the "iss" claim.

How to Reproduce?

Add a hard-coded claim to a client scope that sets the "iss" value, then request an access token.

Anything else?

While having the URL for Keycloak in the "iss" claim makes a lot of sense for a variety of use-cases, I would argue that it is not the right thing to do for every use case. It is a reasonable default but we need to enable people to provide their own value when that is what makes sense for their situation.

In my own experience, I need to perform backend authentication to a third party service. This third party has a clear list of what they need to see in the claims of the token, including a specific value in the "iss" claim. While I don't like this requirement I am powerless to change the mind of this third party (who looms large in the hospital-wide electronic health record space).

By way of filling in some history on this issue, it was originally change in #8680, this PR was addressing issue 14309.

https://issues.redhat.com/browse/KEYCLOAK-14309?attachmentViewMode=list

I have patched my Keycloak instance in order to verify that this was the root cause, the patch is very short. I removed line 111 from the services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java file.

I realize that this may not be the best way to resolve this issue. I would be glad to work on this further and submit a PR, please let me know how I should best proceed.

Thank you for your time! 🙂

@cmiles74 cmiles74 added kind/bug Categorizes a PR related to a bug status/triage labels Apr 25, 2023
@ghost ghost added area/oidc Indicates an issue on OIDC area team/core labels Apr 25, 2023
@mposolda mposolda added kind/feature Categorizes a PR related to a new feature and removed kind/bug Categorizes a PR related to a bug labels Apr 27, 2023
@mposolda
Copy link
Contributor

@cmiles74 Thanks for the report. This is not a bug, but rather a "Feature request" as it is expected behaviour (at least for now) that "iss" is hardcoded to realm URL. We have some plans to expand on this behaviour with the "multitenancy" support being added.

But for now, it is expected behaviour as allow to changing "iss" can have more side-effects on security and other things...

@cmiles74
Copy link
Contributor Author

cmiles74 commented Apr 27, 2023

Up until now I haven't had to dig deep into how the various flows work, I have relied on Keycloak to handle this stuff and it's worked great. My terminology may not be accurate but I want to clarify that I don't need to change the "iss" value in the JWT tokens for every scenario, I only need to change this value when I am creating an access token for a third party service. I believe this is part of RFC 7523.

What happens here is that I have a service (not a person) that needs to authenticate to the third party system in order to do some work. My service asks Keycloak for an access token that it may present to this third party, this token needs to meet certain requirements.

  • It needs the "client ID" provided by the third-party in the "sub" claim
  • It needs the authorization URL of the third-party in the "aud" claim

In my case, this third party also requires the "client ID" that they've provided me to be present in the "iss" claim. While I don't like this and it strikes me as redundant it does appear to be allowed by the specification.

The JWT MUST contain an "iss" (issuer) claim that contains a unique identifier for the entity that issued the JWT.

A URL isn't required and it does sound like the "iss" value should be up to me. But then the RFC goes on to say...

Agreement between system entities regarding identifiers, keys, and endpoints is required in order to achieve interoperable deployments of this profile. Specific items that require agreement are as follows: values for the issuer and audience identifiers, the location of the token endpoint, the key used to apply and verify the digital signature or MAC over the JWT, one-time use restrictions on the JWT, maximum JWT lifetime allowed, and the specific subject and claim requirements of the JWT. The exchange of such information is explicitly out of scope for this specification.

Here the RFC specifically calls out the issuer as something myself and the third party must agree on. Perhaps this is what persuaded this particular third party to make this requirement.

In any case, if these changes for the multi-tenancy feature will resolve this issue that would be good enough for me. Do you know how this proposed feature might work? I worry that it will require a URL and that will not satisfy my use-case.

I appreciate the project's concern for security, indeed this is something I personally appreciate. But in this case, is it possible that this requirement that access tokens contain the Keycloak public URL as the issuer in all situations is conflicting with the project's goal of supporting the various OAuth2 authentication and authorization flows?

There are many relevant RFCs and some replace others as time goes on, this complicates things as Keycloak is expected to support not only the current version but past ones as well. Would a command-line flag to specifically enable this behavior be appropriate in this case? As you mention, this would also resolve the issue for those who need to support multi-tenancy.

Thank you for your time and I apologize for the length of this response. I wanted to make sure I was clearly describing my use case and where I believe the friction is coming from. 🙂

@cmiles74
Copy link
Contributor Author

cmiles74 commented Apr 28, 2023

Issue 15688 is interesting! It looks like they are using the Nimbus OAuth library and that library (until 9/2022) required that the "iss" and "sub" claims be the same. This requirement has been relaxed on the Nimbus side moving forward, but this indicates that there are some existing security practices in place that are in conflict with how Keycloak populates this claim.

@jbman
Copy link

jbman commented May 4, 2023

@cmiles74, seems like you want to use Keycloak to issue JWTs which can be used as Authorization Grants as described by RFC 7523 '.
I just want to link a related idea, which is the other way around: Keycloak could support accepting JWTs as Authorization Grants: #14823

@Cherrywoood
Copy link

Cherrywoood commented Jun 20, 2023

@cmiles74, Hello, do not tell me how to solve the problem. I have keycloak as a resource server for my spring application, and it validates tokens. And when I run a spring application and keycloak in a docker container, I can no longer access keycloak on localhost from spring. However, the token that comes from keycloak has iss:"http://localhost:8180...". Because of this, I get an invalid iss token and I get a 401 error. Can you tell me what to do with this situation? How to run spring and keycloak together in docker?

@CezaryStasiak
Copy link

This is a problem in my org as well. Authorizing via self signed token in Firebase (GCP) requires overriding Issuer value.
Ref: Firebase custom tokens

@allebone
Copy link

allebone commented Oct 28, 2023

This is a common need for third party APIs such Box.com, when using JWT. The Issuer needs to match the service account or else it can’t match to the correct integration and permissions.

Systems like Okta and IBM Verify support this on the SaaS side to better serve Native Mobile and SPA Web Integrations.

https://support.okta.com/help/s/article/What-is-theIssuerlocated-under-the-OpenID-Connect-ID-Token-app-settings-used-for?language=en_US

https://www.ibm.com/docs/en/security-verify?topic=applications-managing-custom-token-types

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/oidc Indicates an issue on OIDC area kind/feature Categorizes a PR related to a new feature status/triage team/core-clients
Projects
None yet
Development

No branches or pull requests

7 participants