I have some problems with the configuration of the Client Credentials flow in my Client app (My Spring Gateway).
My Authorization server is functional and tests with Postman without any problem.
But in my Client application, it seems that the oauth2 configuration is broken without error of compilation.
When I call a protected resource on my server resource, my client application seems to attempt to call an URL in its base and not the authorization server.
See the code
My configuration file:
security:
oauth2:
client:
registration:
apigateway:
provider: apigateway
client-id: apigateway
client-secret: password
scope: generate_token,read,write
authorization-grant-type: client_credentials
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
provider:
apigateway:
token-uri: https://localhost:9001/oauth/token
My Client dependency:
<dependencies>
<!-- ************ SPRING DEPENDENCIES ************ -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
</dependencies>
Configuration of my WebClient:
public class WebClientSecurityCustomizer implements WebClientCustomizer {
private ServerOAuth2AuthorizedClientExchangeFilterFunction securityExchangeFilterFunction;
public WebClientSecurityCustomizer(
ServerOAuth2AuthorizedClientExchangeFilterFunction securityExchangeFilterFunction) {
this.securityExchangeFilterFunction = securityExchangeFilterFunction;
}
#Override
public void customize(WebClient.Builder webClientBuilder) {
SslProvider sslProvider = SslProvider.builder().sslContext(
SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)
)
.defaultConfiguration(SslProvider.DefaultConfigurationType.NONE).build();
TcpClient tcpClient = TcpClient.create().secure(sslProvider);
HttpClient httpClient = HttpClient.from(tcpClient);
ClientHttpConnector httpConnector = new ReactorClientHttpConnector(httpClient);
webClientBuilder.clientConnector(httpConnector);
webClientBuilder.filters((filterFunctions) -> {
if (!filterFunctions.contains(this.securityExchangeFilterFunction)) {
filterFunctions.add(0, this.securityExchangeFilterFunction);
}
});
}
}
#Configuration
public class WebClientSecurityConfiguration {
#Bean
public WebClientSecurityCustomizer webClientSecurityCustomizer(
ReactiveClientRegistrationRepository clientRegistrations) {
// Provides support for an unauthenticated user such as an application
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
// Build up a new WebClientCustomizer implementation to inject the oauth filter
// function into the WebClient.Builder instance
return new WebClientSecurityCustomizer(oauth);
}
/**
* Helper function to include the Spring CLIENT_REGISTRATION_ID_ATTR_NAME in a
* properties Map
*
* #param provider - OAuth2 authorization provider name
* #return consumer properties Map
*/
public static Consumer<Map<String, Object>> getExchangeFilterWith(String provider) {
return ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId(provider);
}
}
My caller on the resource:
return webClientBuilder.build().get().uri(uri+"{accessToken}", accessToken)
.attributes(
WebClientSecurityConfiguration.getExchangeFilterWith("apigateway"))
.retrieve()
.bodyToMono(String.class)
.flatMap(response -> {
ServerHttpRequest request = exchange.getRequest().mutate()
.header(jwtHeader, String.format("%s %s", jwtPrefix, response))
.build();
return chain.filter(exchange.mutate().request(request).build());
});
}
And to finish, the error generated in the client application (it seems that Authorization and resource serve don't receive request):
2019-12-02 13:53:50.543 ERROR 11492 --- [ctor-http-nio-2] a.w.r.e.AbstractErrorWebExceptionHandler : [405f3f3c] 500 Server Error for HTTP GET "/oauth2/authorization/apigateway"
java.lang.IllegalArgumentException: Invalid Authorization Grant Type (client_credentials) for Client Registration with Id: apigateway
at org.springframework.security.oauth2.client.web.server.DefaultServerOAuth2AuthorizationRequestResolver.authorizationRequest(DefaultServerOAuth2AuthorizationRequestResolver.java:156) ~[spring-security-oauth2-client-5.2.1.RELEASE.jar:5.2.1.RELEASE]
Thanks a lot for your help.
Add the below-mentioned class to your spring boot project. Then, it works properly without the above issue.
You need to extend "WebSecurityConfigurerAdapter" for any custom security class.
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/**");
}
}
Related
Recently I have integrated Spring Boot Admin in my application. Everything fine, until I've stared adding security (nothing complicated, just Basic Auth). When I try to login in Spring Boot Admin UI, it redirects me back to the login page with "Login required to access the resource (Error: 401).", or to "variables.css". I am using Spring Boot 3.0.0 with Spring Boot Admin version 3.0.0-M6.
I have to mention that everything works alright if I disable spring security.
Security Config class looks like this:
#Configuration(proxyBeanMethods = false)
#EnableWebSecurity
#AllArgsConstructor
public class AdminSecurityConfig {
private final AdminServerProperties adminServerProperties;
private final SecurityProperties securityProperties;
private final AuthenticationConfiguration authenticationConfiguration;
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(this.adminServerProperties.path("/"));
http
.authorizeHttpRequests(
(authorizeRequests) ->
authorizeRequests.requestMatchers(this.adminServerProperties.path("/assets/**")).permitAll()
.requestMatchers(this.adminServerProperties.path("/*.css")).permitAll()
.requestMatchers(this.adminServerProperties.path("/actuator/info")).permitAll()
.requestMatchers(this.adminServerProperties.path("/actuator/health")).permitAll()
.requestMatchers(this.adminServerProperties.path("/login")).permitAll()
.anyRequest().authenticated()
).formLogin(
(formLogin) -> formLogin.loginPage(this.adminServerProperties.path("/login")).successHandler(successHandler).and()
).logout((logout) -> logout.logoutUrl(this.adminServerProperties.path("/logout")))
.httpBasic(Customizer.withDefaults())
.csrf(
(csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers(
new AntPathRequestMatcher(this.adminServerProperties.path("/instances"),
HttpMethod.POST.name()),
new AntPathRequestMatcher(this.adminServerProperties.path("/instances/*"),
HttpMethod.DELETE.name()),
new AntPathRequestMatcher(this.adminServerProperties.path("/actuator/**"))
));
return http.build();
}
#Bean
public AuthenticationManager authenticationManager() throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
#Bean
public UserDetailsService userDetailsService() {
UserDetails user =
User.withUsername(securityProperties.getUser().getName())
.password("{noop}" + securityProperties.getUser().getPassword())
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
also, I have added this in the application.yaml file
spring:
security:
user:
name: ****
password: ****
roles:
- USER
boot:
admin:
monitor:
status-interval: 30000
status-lifetime: 30000
ui:
title: "Invoice Matching Admin"
remember-me-enabled: false
Main class looks like this:
#EnableAdminServer
#SpringBootApplication
public class InvoiceAdminServiceApplication {
public static void main(String[] args) {
SpringApplication.run(InvoiceAdminServiceApplication.class, args);
}
}
pom.xml contains this dependencies
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
In case that somebody will encounter the same problem, I managed to find the solution.
In the filterChain method you should add this:
.dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll()
Here is a documentation (https://codecentric.github.io/spring-boot-admin/3.0.0-M7/security.html#securing-spring-boot-admin) for Spring Admin security.
I have an application, that currently uses RestTemplate + OAuth2. The application itself is NOT a Spring MVC app, so for example no ports are open (no #GetMapping what so ever).
I am migrating from Spring Security OAuth 2.x to Spring Security 5.2.x. using this guide:
https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Migration-Guide
Config is:
#Configuration
public class WebClientConfig {
#Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
#Bean
public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oauth2Client.setDefaultClientRegistrationId("regid");
return WebClient.builder()
.apply(oauth2Client.oauth2Configuration())
.build();
}
}
application.properties:
spring.security.oauth2.client.registration.regid.provider=regid
spring.security.oauth2.client.registration.regid.client-id=java-web
spring.security.oauth2.client.registration.regid.client-secret=secret
spring.security.oauth2.client.registration.regid.authorization-grant-type=client_credentials
spring.security.oauth2.client.provider.regid.token-uri=https://...token
spring.security.oauth2.client.provider.regid.jwk-set-uri=https://..certs
The problem is:
This app runs on a server that has port 8080 already allocated.
Previous version (Spring Oauth2 + RestTemplate) did NOT open any ports, especially 8080.
It seems that I can not use WebClient without making this app a webapp, listening on port 8080, which I cannot open, and I don't want to change to a random port to avoid collision. The app just simply does not need any ports to be opened.
I've tried several things, for example:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>tomcat-embed-el</artifactId>
<groupId>org.apache.tomcat.embed</groupId>
</exclusion>
<exclusion>
<artifactId>tomcat-embed-core</artifactId>
<groupId>org.apache.tomcat.embed</groupId>
</exclusion>
<exclusion>
<artifactId>tomcat-embed-websocket</artifactId>
<groupId>org.apache.tomcat.embed</groupId>
</exclusion>
</exclusions>
</dependency>
And also:
spring.main.web-application-type=none
etc., but every single time I've encountered a "random" NoClassDefFound javax.servlet.*, or: "Could not autowire. No beans of 'x' type found."
How can I setup the app:
using newest Spring Security with OAuth2
using WebClient
not being a webapp itself
?
thank you
I have a service A which calls service B to get some resource. It works fine when a client calls A with access token and A will relay the token to the request to B.
Now, I am implementing redis to cache data. When I receive a message from B that something is updated, I need to call B to retrieve those updated resource. However, A does not have the access token now and my request is not authrized.
Is there a way to automatically generate an access token?
Thanks for your help.
Got something to work, but not sure whether it is good practice.
I created a separate RestTemplate for this.
Dependency:
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
Enable:
#EnableOAuth2Client
application.yml:
security:
oauth2:
auto:
clientId: <client id>
clientSecret: <client key>
grantType: password
username: <username>
password: <password>
accessTokenUri: <URI>
userAuthorizationUri: <URI>
scope: openid profile email
Configuration:
#Bean
#ConfigurationProperties("security.oauth2.auto")
protected ResourceOwnerPasswordResourceDetails autoOAuth2Details() {
return new ResourceOwnerPasswordResourceDetails();
}
#LoadBalanced
#Bean
protected OAuth2RestTemplate autoRestTemplate(RestTemplateCustomizer customizer) {
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(autoOAuth2Details);
customizer.customize(restTemplate);
return restTemplate;
}
Using this template my service is able to call other services by itself.
Im trying to build a spring gateway which is getting JWT and is sending the tokens to all underlying services. For this I use the following dependencies:
<!-- Spring Boot Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<!-- Spring Boot Dependencies -->
<!-- Spring Cloud Dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Spring Cloud Dependencies -->
I configured my application for Auth0:
spring:
cloud:
gateway:
routes:
- id: my-service
uri: http://localhost:8001/
predicates:
- Path=/comments
filters:
- TokenRelay= #to send the token to the underlying service
- RemoveRequestHeader=Cookie #remove cookies since underlying services don't need them
security:
oauth2:
resourceserver:
jwt:
issuer-uri: #my issuer-uri
audience: #my audience
I implemented the audience validator and the jwt decoder like described here:
#Configuration
#ConditionalOnProperty(name = {"spring.security.oauth2.resourceserver.jwt.issuer-uri"})
public class AuthenticationOauth2Configuration {
#Value("${spring.security.oauth2.resourceserver.jwt.audience}")
private String audience;
#Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuer;
#Bean(name = "customJwtDecoder")
public JwtDecoder getJwtDecoder() {
final NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder) JwtDecoders.fromOidcIssuerLocation(issuer);
final OAuth2TokenValidator<Jwt> audienceValidator = new JwtAudienceValidator(audience);
final OAuth2TokenValidator<Jwt> issuer = JwtValidators.createDefaultWithIssuer(this.issuer);
final OAuth2TokenValidator<Jwt> audience = new DelegatingOAuth2TokenValidator<>(issuer, audienceValidator);
jwtDecoder.setJwtValidator(audience);
return jwtDecoder;
}
}
public class JwtAudienceValidator implements OAuth2TokenValidator<Jwt> {
private final String audience;
public JwtAudienceValidator(final String audience) {
this.audience = audience;
}
#Override
public OAuth2TokenValidatorResult validate(Jwt jwt) {
final OAuth2Error error = new OAuth2Error("invalid_token", "The required audience is missing", null);
if (jwt.getAudience().contains(audience)) {
return OAuth2TokenValidatorResult.success();
}
return OAuth2TokenValidatorResult.failure(error);
}
}
However when Im starting the gateway service im getting the following error:
Caused by: reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalArgumentException: Unable to find GatewayFilterFactory with name TokenRelay
Caused by: java.lang.IllegalArgumentException: Unable to find GatewayFilterFactory with name TokenRelay
I literally cant find any resources on how to fix this.
You need org.springframework.boot:spring-boot-starter-oauth2-client as said here.
But I don't think you need it as soon as you use resource server. Gateway will forward your headers downstream without any configuration, so you will be able to find the authorization header there.
In order for spring cloud gateway to pass tokens to downstream services and validate tokens you need the following dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
To give an example to what Eduard Khachirov said:
dependencies:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
service application.yml:
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://<AUTH0_DOMAIN>/
auth0:
audience: <AUTH0_API_AUDIENCE>
service security config:
#Configuration
#EnableWebSecurity
public class Oauth2ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Value("${auth0.audience}")
private String audience;
#Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuer;
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
#Bean
public JwtDecoder jwtDecoder() {
final NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder) JwtDecoders.fromOidcIssuerLocation(issuer);
jwtDecoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>(
JwtValidators.createDefaultWithIssuer(issuer),
new AudienceValidator(audience)));
return jwtDecoder;
}
static class AudienceValidator implements OAuth2TokenValidator<Jwt> {
private final String audience;
public AudienceValidator(final String audience) {
this.audience = audience;
}
public OAuth2TokenValidatorResult validate(final Jwt jwt) {
if (jwt.getAudience().contains(audience)) {
return OAuth2TokenValidatorResult.success();
}
return OAuth2TokenValidatorResult.failure(new OAuth2Error("invalid_token", "The required audience is missing", null));
}
}
}
gateway application.yml
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://<AUTH0_DOMAIN>/
cloud:
gateway:
routes:
- id: my-service
uri: lb://MY-SERVICE
predicates:
- Path=/api
loadbalancer:
ribbon:
enabled: false
gateway security config:
#Configuration
#EnableWebFluxSecurity
public class Oauth2ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
}
I had the same problem, I needed an OAuth2 consumer acts as a Client and forwards the incoming token to outgoing resource requests.
As I were using a Spring Cloud Gateway embedded reverse proxy then I could ask it to forward OAuth2 access tokens downstream to the services it is proxying. Thus the SSO app above can be enhanced simply like this (using TokenRelay Filter):
spring:
cloud:
gateway:
routes:
- id: resource
uri: http://localhost:9000
predicates:
- Path=/resource
filters:
- TokenRelay=
To enable this for Spring Cloud Gateway add the following dependencies
org.springframework.boot:spring-boot-starter-oauth2-client
org.springframework.cloud:spring-cloud-starter-security.
I had this pom.xml configuration:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-core</artifactId>
<version>${springdoc.openapi.webflux}</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-ui</artifactId>
<version>${springdoc.openapi.webflux}</version>
</dependency>
</dependencies>
Trying to upgrade existing resource services from Spring Boot 1.x to 2.x. Spring Security 4.5 is running on the authentication server and encodes JWT tokens like this:
#Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(privateKey);
converter.setVerifierKey(publicKey);
return converter;
}
A resource server upgraded to Spring Boot 2.1.3.RELEASE throws this error:
OAuth2AuthenticationProcessingFilter:165 :
Authentication request failed: error="invalid_token",
error_description="Invalid access token:****..."
The log reveals that the OAuth2AuthenticationProcessingFilter is using the MappingJackson2HttpMessageConverter to extract the JWT token. Spring Security auto-configuration should provide the JwtAccessTokenConverter bean instead of the MappingJackson2HttpMessageConverter bean since there is a key-value in my properties file:
security:
oauth2:
resource:
jwt:
key-value: |
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
Here is the Spring Security ResourceServerTokenServiceConfiguration class that should detect it. The property matches "security.oauth2.resource.jwt.key-value".
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
ConditionMessage.Builder message = ConditionMessage
.forCondition("OAuth JWT Condition");
Environment environment = context.getEnvironment();
String keyValue = environment
.getProperty("security.oauth2.resource.jwt.key-value");
String keyUri = environment
.getProperty("security.oauth2.resource.jwt.key-uri");
if (StringUtils.hasText(keyValue) || StringUtils.hasText(keyUri)) {
return ConditionOutcome
.match(message.foundExactly("provided public key"));
}
return ConditionOutcome
.noMatch(message.didNotFind("provided public key").atAll());
}
These are the resource server security dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
This is the resource server configuration. It is essentially the same as it was with Spring Boot 1.5.x.
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "my-service";
#Override
public void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID);
}
}
What am I missing?
The problem was an issue with the properties. I had moved "security.oauth2" to "spring.security.oauth2." When I turned on logging for org.springframework.boot.autoconfigure.security.oauth2 and saw this:
did not match due to OAuth Client ID did not find security.oauth2.client.client-id property
So, I decided to try moving the oauth2 properties back out from under "spring." and it was able to extract the JWT token.