Steve Mitchell
Steve Mitchell

Reputation: 11

Decode Spring Boot 2.1 OAuth2 encoded JWT on Resource Server

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?

Upvotes: 0

Views: 2476

Answers (1)

Steve Mitchell
Steve Mitchell

Reputation: 90

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.

Upvotes: 0

Related Questions