-
Notifications
You must be signed in to change notification settings - Fork 6k
Support for setting different 'jwk-set-uri's for each JWT in OAuth 2.0 Resource Server Multi-tenancy #13808
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
Comments
You might find this Spring Boot starter I wrote useful. Your use case is covered as so: <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-starter-oidc</artifactId>
<version>7.1.8</version>
</dependency> @Configuration
@EnableReactiveMethodSecurity // @EnableMethodSecurity in a servlet
public class SecurityConfig {
} com:
c4-soft:
springaddons:
oidc:
ops:
- iss: https://s1.host.name
jwk-set-uri: original.jwks.server:8080/.well-known/jwks.json
authorities:
# this is an array: you can define as many JSON path as you need
# you can also add basic transformation for each (prefix and force to upper / lower case)
- path: $.json-path.to.claim.to.use.as.authorities.source
- iss: https://s2.host.name
jwk-set-uri: new.jwks.server:8080/.well-known/jwks.json
authorities:
- path: $.json-path.to.claim.to.use.as.authorities.source
resourceserver:
permit-all:
- "/public/**" In addition to the "static" multi-tenancy your are looking for, it provides with quite a few other features you might find useful
It is compatible with both reactive and servlet applications. It is also compatible with OAuth2 clients (even if there are some caveats with multi-tenancy on clients) |
@ch4mpy Thank you for reply and your commitment to spring-addons which is such a great open source project. |
still think this functionality is really needed as native to the spring security resource server it self. I hope it gets attention. would be lovely. |
Thanks for reaching out, @sgc109. You can configure @Bean
JwtIssuerAuthenticationManagerResolver authenticationManagerResolver() {
Map<String, JwtDecoder> decoders = Map.of(
"https://s1.host.name", decoder("original.jwks.server:8080/.well-known/jwks.json"),
"https://s2.host.name", decoder("new.jwks.server:8080/.well-known/jwks.json"));
return new JwtIssuerAuthenticationManagerResolver(decoders::get);
}
JwtDecoder decoder(String jwkSetUri) {
return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
} As for enhancing the Spring Boot properties, please see spring-projects/spring-boot#30108 for the latest discussion about that. If you feel you have more to add, please contribute it to that ticket so we can keep the conversation in one place. |
Passing a Map<String, JwtDecoder> is deprecated in Spring Framework 6.2 so this solution will break in Spring Boot 3.3.x ![]() |
Just a note to point that multi-tenancy support for resource servers has recently improved in
As illustration, here is how you can accept tokens from any realm of a Keycloak instance (again, even if the realm is created after the resource server was started): com:
c4-soft:
springaddons:
oidc:
ops:
- iss: https://oidc.c4-soft.com/auth/realms/
authorities:
- path: $.realm_access.roles @Component
public class IssuerStartsWithOpenidProviderPropertiesResolver implements OpenidProviderPropertiesResolver {
private final SpringAddonsOidcProperties properties;
public IssuerStartsWithOpenidProviderPropertiesResolver(SpringAddonsOidcProperties properties) {
this.properties = properties;
}
@Override
public Optional<OpenidProviderProperties> resolve(Map<String, Object> claimSet) {
final var tokenIss = Optional
.ofNullable(claimSet.get(JwtClaimNames.ISS))
.map(Object::toString)
.orElseThrow(() -> new RuntimeException("Invalid token: missing issuer"));
return properties.getOps().stream().filter(opProps -> {
final var opBaseHref = Optional.ofNullable(opProps.getIss()).map(URI::toString).orElse(null);
if (!StringUtils.hasText(opBaseHref)) {
return false;
}
return tokenIss.startsWith(opBaseHref);
}).findAny();
}
} You can easily write similar components for scenarios where you need to trust issuers from given (sub)domains, listed in any sort of datasource, or whatever. Complete list of features in the module README. |
My apologies, I had a typo in my sample. Here is what is supported (and not deprecated): @Bean
JwtIssuerAuthenticationManagerResolver authenticationManagerResolver() {
Map<String, JwtDecoder> decoders = Map.of(
"https://s1.host.name", manager("original.jwks.server:8080/.well-known/jwks.json"),
"https://s2.host.name", manager("new.jwks.server:8080/.well-known/jwks.json"));
return new JwtIssuerAuthenticationManagerResolver(decoders::get);
}
AuthenticationManager authenticationManager(String jwkSetUri) {
JwtDecoder decoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
JwtAuthenticationProvider provider = new JwtAuthenticationProvider(decoder);
return new ProviderManager(provider);
} That said, I'd encourage you to follow #14677 as I believe that will reduce some of the boilerplate you are having to do. |
Expected Behavior
I thought it can't be better if I can just list sets of information for each JWT format(issuer, jwk-set-uri, ...) in application.yaml like below(It's just an example. So it might not be compatible with another configurations of Spring Security OAuth2).
But, I found that these kind of configuration is not possible at the moment.
If support like above is not easy right now, it'd be really nice if I can configure different 'jwk-set-uri's for each issuer with using JwtIssuerReactiveAuthenticationManagerResolver.
According to documentation of it, I can just set multiple issuers, but not able to set different jwt-set-uris.
Current Behavior
Just support one set of jwk-set-uri and issuer like below.
And can't configure multiple jwk-set-uris associating with multiple issuers with using JwtIssuerReactiveAuthenticationManagerResolver, which is for OAuth2 resource server multi-tenancy.
Context
Let me explain about my situation.
Our service is using JWT in Resource Server issued by an Authorization Server(Let's call it S1).
Also, we should have specific jwk-set-uri which is separated from issuer.
application.yaml is like below.
Now we are replacing original Authorization Server(S1) to new one(S2) for issuing.
And new issuer also has its own jwk-set-uri.
In order for backward compatibility, we should permit original JWT format(issuer & jwk-set-uri) and, at the same time, new JWT format.
The text was updated successfully, but these errors were encountered: