Expected Behavior

It is possible to define multiple issuer URIs at spring.security.oauth2.resourceserver.issuer-uris. Spring Security considers all configured JWK Issuers to validate tokens.

Current Behavior

Only one JWK issuer can be configured.

Context

We are building a service that will run in multiple regions. For service-to-service authorization, we are using JWTs that are signed with JWKs which are specific to the region that the requesting service is deployed to (concretely, we are using k8s’ service account tokens). In failure scenarios, client services shall fail over to a service that is deployed in a different region. Hence, our service needs to be able to validate tokens from all regions that our clients might be deployed in.

In a comment on #7474 somebody requested functionality to have different JWK sets for different types of tenants. It was explained that this should be solved via an AuthenticationManagerResolver. We think that our use case is different. We do not have different types of tenants. Instead, we only have one type of tenant, but different potential issuers for tokens.

Implementation Considerations

We are willing to provide a PR for this functionality. Our current design considerations are below. We would be happy to receive feedback!

  1. Must a PR that provides this functionality implement it for both the blocking and the reactive implementation? Or would an implementation only for reactive be acceptable?
  2. Our proposed implementation is to create a ReactiveJwtDecoder that dispatches to delegate ReactiveJwtDecoders based on the iss claim in a JWT. The delegates would be configured for every issuer URI like they are today.
  3. A disadvantage of the above proposal is that we would have to parse the JWT twice: once in the dispatching ReactiveJwtDecoder, and once in the actual ReactiveJwtDecoder. The alternative we see is to make the builders in NimbusReactiveJwtDecoder aware of the issuer checks. We could then build just one NimbusReactiveJwtDecoder with a jwtProcessor that does the dispatching based on iss to the correct jwtProcessor. This setup would avoid the double parsing, but would likely also be more complicated in the code, especially because the issuer concern is pulled into the already elaborate builders in NimbusReactiveJwtDecoder. We would welcome guidance on the best approach here!
  4. What is the appropriate deprecation strategy for the single-value property issuer-uri? Should it be marked deprecated in favour of issuer-uris? Or should the former be appended to the latter?
  5. spring-security currently supports the iss check if one configures a jwk-set-uri together with an issuer-uri. Would it be required to support this feature also for multiple JWK Set URIs? If so, how should the mapping of the JWK Set URIs to the expected Issuer URIs happen? Should they just be declared as lists in the same order?
  6. spring-security currently checks the Issuer URI synchronously on startup. Given our use case, we don’t want the application startup to fail just because one issuer could not be reached, since other regions should remain functional if one region goes down. A conservative approach would be to let the startup succeed if at least one issuer could be reached. However, it would then be good to re-check the failed issuers from time to time, so that they can become functional again without having to restart the service. I think the details can be done in a separate PR. It would potentially mean introducing proxy ReactiveJwtDecoders that act while the issuer is down, check the issuer periodically, and switch to the actual ReactiveJwtDecoder once the issuer was reached.

(updated to reflect better understandig of the implementation)

Comment From: jzheaux

Hi, @jGleitz, thanks for the detailed write-up.

We do not have different types of tenants. Instead, we only have one type of tenant, but different potential issuers for tokens.

This still seems to be something that JwtIssuerAuthenticationManagerResolver can handle and is intended for. Have you already tried using it, and if so, where did you get into trouble with that approach?

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: jGleitz

Hi! Thank you for your response. We noticed that

a) I misunderstood the purpose of JwtIssuerAuthenticationManagerResolver and it might suit our use case, we have to check. b) we might be able to pull authorization concerns out of the service and into the service mesh.

We are going to close this issue for now until we have checked everything on our side, and will get back if we think that there is an area where Spring Security could be improved.

Thank you for your support!