From 29b03edf6f638c6e024e446742f1844b02ca0be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Fri, 27 Mar 2026 11:11:22 +0100 Subject: [PATCH] Do not configure a ReactiveJmtDecoder without spring-webflux This commit guards the creation of a ReactiveJwtDecoder with the presence of Spring WebFlux. WebClient is used behind the scenes and the sole presences of the authorization server and reactive types were not precise enough. Closes gh-49807 --- .../reactive/ReactiveJwtDecoderConfiguration.java | 3 +++ ...tiveOAuth2ResourceServerAutoConfigurationTests.java | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveJwtDecoderConfiguration.java b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveJwtDecoderConfiguration.java index 28e0eca5f93..820b57044cb 100644 --- a/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveJwtDecoderConfiguration.java +++ b/module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveJwtDecoderConfiguration.java @@ -31,6 +31,7 @@ import java.util.Set; import org.jspecify.annotations.Nullable; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException; @@ -53,6 +54,7 @@ import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; import org.springframework.security.oauth2.jwt.SupplierReactiveJwtDecoder; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; +import org.springframework.web.reactive.function.client.WebClient; /** * {@link Configuration @Configuration} for reactive JWT decoder beans. @@ -67,6 +69,7 @@ import org.springframework.util.CollectionUtils; * @author Phillip Webb */ @Configuration(proxyBeanMethods = false) +@ConditionalOnClass(WebClient.class) @ConditionalOnMissingBean(ReactiveJwtDecoder.class) class ReactiveJwtDecoderConfiguration { diff --git a/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java b/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java index 0e482298653..e7e9b473801 100644 --- a/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java +++ b/module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java @@ -83,6 +83,7 @@ import org.springframework.security.oauth2.server.resource.authentication.Reacti import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector; import org.springframework.security.web.server.SecurityWebFilterChain; import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.reactive.function.client.WebClient; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -300,6 +301,15 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests { }); } + @Test + void autoConfigurationShouldBackOffIfWebClientIsNotAvailable() { + this.contextRunner.withClassLoader(new FilteredClassLoader(WebClient.class)) + .withPropertyValues("spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com") + .run((context) -> assertThat(context).hasNotFailed() + .doesNotHaveBean(NimbusReactiveJwtDecoder.class) + .doesNotHaveBean(ReactiveJwtDecoder.class)); + } + @Test void autoConfigurationShouldFailIfPublicKeyLocationDoesNotExist() { this.contextRunner