'Spring OAuth2: Always returning invalid token

I am trying to implement an OAuth2-Server with one Resource Server using Spring Boot. I am able to request tokens but if I use them to request resources from the Resource server the result is always 'invalid token'.

This is the authorization server configuration:

@Configuration
@EnableAuthorizationServer
public class AuthserverConfiguration extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authorizationCodeServices(authorizationCodeServices())
        // injects the Spring Security authentication manager (set up in WebSecurityConfiguration )
                .authenticationManager(authenticationManager)
                .tokenStore(tokenStore());
    }
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        // configure security for /oauth/check_token and /oauth/token_key endpoint
        security.tokenKeyAccess("permitAll()")
                .checkTokenAccess("permitAll()"); // should be isAuthenticated()

    }
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("clientId").secret("{noop}clientsecret")
                .authorizedGrantTypes("authorization_code", "refresh_token", "password")
                .scopes("read");
    }
    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }
    @Bean
    protected AuthorizationCodeServices authorizationCodeServices() {
        // creates authorization codes, stores the codes in memory.
        return new InMemoryAuthorizationCodeServices();
    }
}

WebSecurityConfiguration is:

@EnableWebSecurity
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 20)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user").password("{noop}password").roles("USER");
        /* for now testing with inMemoryAuthentication, later I want to use: 
         * auth.userDetailsService(userDetailsService); */
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
            .and()
            .formLogin().loginPage("/login").permitAll().failureUrl("/login?error")
            .and()
            .authorizeRequests().anyRequest().authenticated();
    }

    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

And the UserInfoController:

@RestController
public class UserInfoController {

    @RequestMapping(value = "/user")
    public Principal userInfo(@AuthenticationPrincipal Principal user) {
        return user;
    }
}

pom.xml contains the following dependencies:+

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security.oauth</groupId>
        <artifactId>spring-security-oauth2</artifactId>
        <version>2.0.5.RELEASE</version>
    </dependency>
</dependencies>

The Resource server on the other hand is a standard Spring Boot project with tomcat, listening to GET /products (returning a list in JSON format) on port 8081. The servers main class is annotated with @EnableResourceServer and its configuration contains:

security:
  oauth2:
    resource:
      user-info-uri: http://localhost:8090/user

where 8090 is the port of above mentioned authentication server.

Testing with curl:

> curl clientId:clientsecret@localhost:8090/oauth/token -d grant_type=password -d username=user -d password=password -d scope=read`
{"access_token":"1cdd6dc2-42fe-4b55-b16d-78d189a88cc4","token_type":"bearer","refresh_token":"d59d78b5-43c8-4d12-b4ee-007da8548744","expires_in":43199,"scope":"read"}

> curl -H 'Authorization: Bearer 1cdd6dc2-42fe-4b55-b16d-78d189a88cc4' 'localhost:8090/oauth/check_token?token=1cdd6dc2-42fe-4b55-b16d-78d189a88cc4'
{"exp":1561956415,"user_name":"user","authorities":["ROLE_USER"],"client_id":"clientId","scope":["read"]}+ set +o xtrace

The token seems to be valid and recognized (if I tamper with the token I get a different error: "unrecognized token").

But if I try to request data from the Resource Server using the token:

> curl -H 'Authorization: Bearer 1cdd6dc2-42fe-4b55-b16d-78d189a88cc4' localhost:8081/products
{"error":"invalid_token","error_description":"Invalid access token: 1cdd6dc2-42fe-4b55-b16d-78d189a88cc4"}

This error is very consistent, I tried a lot of different changes to the configuration and even adding custom implementations of TokenServices, UserDetailsService, etc.

In the debug logs I find the following line in the output of the resource server everytime I do the request via curl:

Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@2b139cc0: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS

This is confusing to me because the Principal should not be anonymousUser in my understanding.

How can I solve this problem and request the data from my resource server? Any help highly appreciated.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source