diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml
index ceb8d168dc..6140047e77 100755
--- a/spring-boot-project/spring-boot-autoconfigure/pom.xml
+++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml
@@ -553,6 +553,11 @@
spring-security-oauth2-client
true
+
+ org.springframework.security
+ spring-security-oauth2-resource-server
+ true
+
org.springframework.session
spring-session-core
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java
new file mode 100644
index 0000000000..3758be17ed
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/OAuth2ResourceServerProperties.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.boot.autoconfigure.security.oauth2.resource;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * OAuth 2.0 resource server properties.
+ *
+ * @author Madhura Bhave
+ */
+@ConfigurationProperties(prefix = "spring.security.oauth2.resource")
+public class OAuth2ResourceServerProperties {
+
+ private Jwt jwt = new Jwt();
+
+ public Jwt getJwt() {
+ return this.jwt;
+ }
+
+ public void setJwt(Jwt jwt) {
+ this.jwt = jwt;
+ }
+
+ public static class Jwt {
+
+ private Jwk jwk = new Jwk();
+
+ public Jwk getJwk() {
+ return this.jwk;
+ }
+
+ public void setJwk(Jwk jwk) {
+ this.jwk = jwk;
+ }
+
+ }
+
+ public static class Jwk {
+
+ /**
+ * The URI to get verification keys to verify the JWT token.
+ */
+ private String setUri;
+
+ public String getSetUri() {
+ return this.setUri;
+ }
+
+ public void setSetUri(String setUri) {
+ this.setUri = setUri;
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/package-info.java
new file mode 100644
index 0000000000..ff8ebd6d02
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Support for Spring Security's OAuth 2 resource server.
+ */
+package org.springframework.boot.autoconfigure.security.oauth2.resource;
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfiguration.java
new file mode 100644
index 0000000000..d2685b3965
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfiguration.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
+
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
+import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for OAuth resource server support.
+ *
+ * @author Madhura Bhave
+ * @since 2.1.0
+ */
+@Configuration
+@AutoConfigureBefore(SecurityAutoConfiguration.class)
+@EnableConfigurationProperties(OAuth2ResourceServerProperties.class)
+@ConditionalOnClass(JwtAuthenticationToken.class)
+@Import({ OAuth2ResourceServerJwkConfiguration.class,
+ OAuth2ResourceServerWebSecurityConfiguration.class })
+public class OAuth2ResourceServerAutoConfiguration {
+
+}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java
new file mode 100644
index 0000000000..8180ca1405
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerJwkConfiguration.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.jwt.JwtDecoder;
+import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport;
+
+/**
+ * Configures a {@link JwtDecoder} when a JWK Set URI is available.
+ *
+ * @author Madhura Bhave
+ */
+@Configuration
+class OAuth2ResourceServerJwkConfiguration {
+
+ private final OAuth2ResourceServerProperties properties;
+
+ public OAuth2ResourceServerJwkConfiguration(
+ OAuth2ResourceServerProperties properties) {
+ this.properties = properties;
+ }
+
+ @Bean
+ @ConditionalOnProperty(name = "spring.security.oauth2.resource.jwt.jwk.set-uri")
+ @ConditionalOnMissingBean
+ public JwtDecoder jwtDecoder() {
+ return new NimbusJwtDecoderJwkSupport(
+ this.properties.getJwt().getJwk().getSetUri());
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java
new file mode 100644
index 0000000000..7a6e6f31b5
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerWebSecurityConfiguration.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.oauth2.jwt.JwtDecoder;
+
+/**
+ * {@link WebSecurityConfigurerAdapter} for OAuth2 resource server support.
+ *
+ * @author Madhura Bhave
+ */
+@Configuration
+@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
+@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
+class OAuth2ResourceServerWebSecurityConfiguration {
+
+ @Configuration
+ @ConditionalOnBean(JwtDecoder.class)
+ static class OAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
+
+ protected void configure(HttpSecurity http) throws Exception {
+ http.authorizeRequests().anyRequest().authenticated().and().oauth2()
+ .resourceServer().jwt();
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/package-info.java
new file mode 100644
index 0000000000..bdde811133
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Auto-configuration for Spring Security's OAuth 2 resource server.
+ */
+package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
index 3b49f16c6f..c8dd4ff1da 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -105,6 +105,7 @@ org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
+org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskExecutorAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java
new file mode 100644
index 0000000000..78ba79f0fe
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/servlet/OAuth2ResourceServerAutoConfigurationTests.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
+
+import java.util.List;
+
+import javax.servlet.Filter;
+
+import org.junit.Test;
+
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.FilteredClassLoader;
+import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
+import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.BeanIds;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.oauth2.jwt.JwtDecoder;
+import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport;
+import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
+import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter;
+import org.springframework.security.web.FilterChainProxy;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link OAuth2ResourceServerAutoConfiguration}.
+ *
+ * @author Madhura Bhave
+ */
+public class OAuth2ResourceServerAutoConfigurationTests {
+
+ private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
+ .withConfiguration(
+ AutoConfigurations.of(OAuth2ResourceServerAutoConfiguration.class))
+ .withUserConfiguration(TestConfig.class);
+
+ @Test
+ public void autoConfigurationShouldConfigureResourceServer() {
+ this.contextRunner.withPropertyValues(
+ "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com")
+ .run((context) -> {
+ assertThat(context.getBean(JwtDecoder.class))
+ .isInstanceOf(NimbusJwtDecoderJwkSupport.class);
+ assertThat(getBearerTokenFilter(context)).isNotNull();
+ });
+ }
+
+ @Test
+ public void autoConfigurationWhenJwkSetUriNullShouldNotFail() {
+ this.contextRunner
+ .run((context) -> assertThat(getBearerTokenFilter(context)).isNull());
+ }
+
+ @Test
+ public void jwtDecoderBeanIsConditionalOnMissingBean() {
+ this.contextRunner.withPropertyValues(
+ "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com")
+ .withUserConfiguration(JwtDecoderConfig.class)
+ .run((context) -> assertThat(getBearerTokenFilter(context)).isNotNull());
+ }
+
+ @Test
+ public void autoConfigurationShouldBeConditionalOnJwtAuthenticationTokenClass() {
+ this.contextRunner.withPropertyValues(
+ "spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com")
+ .withUserConfiguration(JwtDecoderConfig.class)
+ .withClassLoader(new FilteredClassLoader(JwtAuthenticationToken.class))
+ .run((context) -> assertThat(getBearerTokenFilter(context)).isNull());
+ }
+
+ @SuppressWarnings("unchecked")
+ private Filter getBearerTokenFilter(AssertableWebApplicationContext context) {
+ FilterChainProxy filterChain = (FilterChainProxy) context
+ .getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
+ List filterChains = filterChain.getFilterChains();
+ List filters = (List) ReflectionTestUtils
+ .getField(filterChains.get(0), "filters");
+ return filters.stream()
+ .filter((f) -> f instanceof BearerTokenAuthenticationFilter).findFirst()
+ .orElse(null);
+ }
+
+ @Configuration
+ @EnableWebSecurity
+ static class TestConfig {
+
+ }
+
+ @Configuration
+ @EnableWebSecurity
+ static class JwtDecoderConfig {
+
+ @Bean
+ public JwtDecoder decoder() {
+ return mock(JwtDecoder.class);
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
index 7343cefff1..22c461b96d 100644
--- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
+++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
@@ -529,6 +529,9 @@ content into your application. Rather, pick only the properties that you need.
spring.security.oauth2.client.provider.*= # OAuth provider details.
spring.security.oauth2.client.registration.*= # OAuth client registrations.
+ # SECURITY OAUTH2 RESOURCE SERVER ({sc-spring-boot-autoconfigure}/security/oauth2/resource/OAuth2ResourceServerProperties.{sc-ext}[OAuth2ResourceServerProperties])
+ spring.security.oauth2.resource.jwt.jwk.set-uri.*= # JWK Set URI
+
# ----------------------------------------
# DATA PROPERTIES
# ----------------------------------------
diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
index fb243687d3..e0284ba337 100644
--- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
+++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
@@ -3276,12 +3276,26 @@ Provider can be configured with the `issuer-uri`:
[[boot-features-security-oauth2-server]]
-==== Server
+==== Resource Server
+If you have `spring-security-oauth2-resource-server` on your classpath, you can take advantage of
+some auto-configuration to make it easy to set up an OAuth2 Resource Server. This configuration
+makes use of the properties under `OAuth2ResourceServerProperties`.
+
+For the OAuth2 Resource Server auto-configuration to kick in, you can
+provide a bean of type `JwtDecoder` yourself or configure a JWK Set URI as follows:
+
+[source,properties,indent=0]
+----
+ spring.security.oauth2.resource.jwt.jwk.set-uri=https://example.com/oauth2/default/v1/keys
+----
+
+
+==== Authorization Server
Currently, Spring Security does not provide support for implementing an OAuth 2.0
-Authorization Server or Resource Server. However, this functionality is available from
+Authorization Server. However, this functionality is available from
the https://projects.spring.io/spring-security-oauth/[Spring Security OAuth] project,
which will eventually be superseded by Spring Security completely. Until then, you can
-use the `spring-security-oauth2-autoconfigure` module to easily set up an OAuth 2.0 server;
+use the `spring-security-oauth2-autoconfigure` module to easily set up an OAuth 2.0 authorization server;
see its https://docs.spring.io/spring-security-oauth2-boot[documentation] for instructions.
diff --git a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/pom.xml b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/pom.xml
new file mode 100644
index 0000000000..649d19b77d
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/pom.xml
@@ -0,0 +1,60 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-samples
+ ${revision}
+
+ spring-boot-sample-oauth2-resource-server
+ Spring Boot Sample OAuth2 Resource Server
+ Spring Boot Sample Resource Server
+
+ ${basedir}/../..
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.security
+ spring-security-config
+
+
+ org.springframework.security
+ spring-security-oauth2-resource-server
+
+
+ org.springframework.security
+ spring-security-oauth2-jose
+
+
+
+ com.squareup.okhttp3
+ mockwebserver
+ 3.9.0
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/ExampleController.java b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/ExampleController.java
new file mode 100644
index 0000000000..00a7be9743
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/ExampleController.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package sample.oauth2.resource;
+
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.security.oauth2.jwt.Jwt;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class ExampleController {
+
+ @GetMapping("/")
+ public String index(@AuthenticationPrincipal Jwt jwt) {
+ return String.format("Hello, %s!", jwt.getSubject());
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/SampleOauth2ResourceServerApplication.java b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/SampleOauth2ResourceServerApplication.java
new file mode 100644
index 0000000000..f80400458e
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/java/sample/oauth2/resource/SampleOauth2ResourceServerApplication.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package sample.oauth2.resource;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SampleOauth2ResourceServerApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SampleOauth2ResourceServerApplication.class);
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/resources/application.yml
new file mode 100644
index 0000000000..2599bf4091
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/main/resources/application.yml
@@ -0,0 +1,8 @@
+spring:
+ security:
+ oauth2:
+ resource:
+ jwt:
+ jwk:
+ # To run the application, replace this with a valid JWK Set URI
+ set-uri: https://example.com/oauth2/default/v1/keys
\ No newline at end of file
diff --git a/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java
new file mode 100644
index 0000000000..062bf013f1
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-oauth2-resource-server/src/test/java/sample/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2012-2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package sample.oauth2.resource;
+
+import java.io.IOException;
+
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class SampleOauth2ResourceServerApplicationTests {
+
+ private static MockWebServer server = new MockWebServer();
+
+ private static final String VALID_TOKEN = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0Iiwic2NvcGUiOiJtZXNzYWdlOnJlYWQi"
+ + "LCJleHAiOjQ2ODM4MDUxNDF9.h-j6FKRFdnTdmAueTZCdep45e6DPwqM68ZQ8doIJ1exi9YxAlbWzOwId6Bd0L5YmCmp63gGQgsBUBLzwnZQ8kLUgU"
+ + "OBEC3UzSWGRqMskCY9_k9pX0iomX6IfF3N0PaYs0WPC4hO1s8wfZQ-6hKQ4KigFi13G9LMLdH58PRMK0pKEvs3gCbHJuEPw-K5ORlpdnleUTQIwIN"
+ + "afU57cmK3KocTeknPAM_L716sCuSYGvDl6xUTXO7oPdrXhS_EhxLP6KxrpI1uD4Ea_5OWTh7S0Wx5LLDfU6wBG1DowN20d374zepOIEkR-Jnmr_Ql"
+ + "R44vmRqS5ncrF-1R0EGcPX49U6A";
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ server.start();
+ String url = server.url("/.well-known/jwks.json").toString();
+ server.enqueue(mockResponse());
+ System.setProperty("spring.security.oauth2.resource.jwt.jwk.set-uri", url);
+ }
+
+ @AfterClass
+ public static void shutdown() throws IOException {
+ server.shutdown();
+ System.clearProperty("spring.security.oauth2.resource.jwt.jwk.set-uri");
+ }
+
+ @Test
+ public void withValidBearerTokenShouldAllowAccess() {
+ HttpHeaders headers = new HttpHeaders();
+ headers.setBearerAuth(VALID_TOKEN);
+ HttpEntity> request = new HttpEntity(headers);
+ ResponseEntity entity = this.restTemplate.exchange("/", HttpMethod.GET,
+ request, String.class);
+ assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
+ }
+
+ @Test
+ public void withNoBearerTokenShouldNotAllowAccess() {
+ HttpHeaders headers = new HttpHeaders();
+ HttpEntity> request = new HttpEntity(headers);
+ ResponseEntity entity = this.restTemplate.exchange("/", HttpMethod.GET,
+ request, String.class);
+ assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
+ }
+
+ private static MockResponse mockResponse() {
+ String body = "{\"keys\":[{\"p\":\"2p-ViY7DE9ZrdWQb544m0Jp7Cv03YCSljqfim9pD4ALhObX0OrAznOiowTjwBky9JGffMw"
+ + "DBVSfJSD9TSU7aH2sbbfi0bZLMdekKAuimudXwUqPDxrrg0BCyvCYgLmKjbVT3zcdylWSog93CNTxGDPzauu-oc0XPNKCXnaDpNvE\""
+ + ",\"kty\":\"RSA\",\"q\":\"sP_QYavrpBvSJ86uoKVGj2AGl78CSsAtpf1ybSY5TwUlorXSdqapRbY69Y271b0aMLzlleUn9ZTBO"
+ + "1dlKV2_dw_lPADHVia8z3pxL-8sUhIXLsgj4acchMk4c9YX-sFh07xENnyZ-_TXm3llPLuL67HUfBC2eKe800TmCYVWc9U\",\"d\""
+ + ":\"bn1nFxCQT4KLTHqo8mo9HvHD0cRNRNdWcKNnnEQkCF6tKbt-ILRyQGP8O40axLd7CoNVG9c9p_-g4-2kwCtLJNv_STLtwfpCY7"
+ + "VN5o6-ZIpfTjiW6duoPrLWq64Hm_4LOBQTiZfUPcLhsuJRHbWqakj-kV_YbUyC2Ocf_dd8IAQcSrAU2SCcDebhDCWwRUFvaa9V5eq0"
+ + "851S9goaA-AJz-JXyePH6ZFr8JxmWkWxYZ5kdcMD-sm9ZbxE0CaEk32l4fE4hR-L8x2dDtjWA-ahKCZ091z-gV3HWtR2JOjvxoNRjxUo"
+ + "3UxaGiFJHWNIl0EYUJZu1Cb-5wIlEI7wPx5mwQ\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"one\",\"qi\":\"qS0OK4"
+ + "8M2CIAA6_4Wdw4EbCaAfcTLf5Oy9t5BOF_PFUKqoSpZ6JsT5H0a_4zkjt-oI969v78OTlvBKbmEyKO-KeytzHBAA5CsLmVcz0THrMSg6o"
+ + "XZqu66MPnvWoZN9FEN5TklPOvBFm8Bg1QZ3k-YMVaM--DLvhaYR95_mqaz50\",\"dp\":\"Too2NozLGD1XrXyhabZvy1E0EuaVFj0UHQ"
+ + "PDLSpkZ_2g3BK6Art6T0xmE8RYtmqrKIEIdlI3IliAvyvAx_1D7zWTTRaj-xlZyqJFrnXWL7zj8UxT8PkB-r2E-ILZ3NAi1gxIWezlBTZ8"
+ + "M6NfObDFmbTc_3tJkN_raISo8z_ziIE\",\"dq\":\"U0yhSkY5yOsa9YcMoigGVBWSJLpNHtbg5NypjHrPv8OhWbkOSq7WvSstBkF"
+ + "k5AtyFvvfZLMLIkWWxxGzV0t6f1MoxBtttLrYYyCxwihiiGFhLbAdSuZ1wnxcqA9bC7UVECvrQmVTpsMs8UupfHKbQBpZ8OWAqrn"
+ + "uYNNtG4_4Bt0\",\"n\":\"lygtuZj0lJjqOqIWocF8Bb583QDdq-aaFg8PesOp2-EDda6GqCpL-_NZVOflNGX7XIgjsWHcPsQHs"
+ + "V9gWuOzSJ0iEuWvtQ6eGBP5M6m7pccLNZfwUse8Cb4Ngx3XiTlyuqM7pv0LPyppZusfEHVEdeelou7Dy9k0OQ_nJTI3b2E1WBoHC5"
+ + "8CJ453lo4gcBm1efURN3LIVc1V9NQY_ESBKVdwqYyoJPEanURLVGRd6cQKn6YrCbbIRHjqAyqOE-z3KmgDJnPriljfR5XhSGyM9eq"
+ + "D9Xpy6zu_MAeMJJfSArp857zLPk-Wf5VP9STAcjyfdBIybMKnwBYr2qHMT675hQ\"}]}";
+ return new MockResponse()
+ .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
+ .setResponseCode(200).setBody(body);
+ }
+
+}
\ No newline at end of file