Search code examples
springspring-securityoauth-2.0spring-bootspring-security-oauth2

Spring Boot OAuth2 - Could not obtain user details from token


I searched the web for solution of this problem but didn't find any working solution. I'm trying to setup basic Spring Boot OAuth2 Authorization Provider and Client.

I followed official Spring Boot instructions and created single sign on with Facebook and Github. Then i followed instructions to create Secure Spring Boot Web application.

I wanted to create my own Authorization Server so I added @EnableAuthorizationServer annotation to Secure Web Application as explained here. I also added details of an OAuth2 client as described in a link. I followed further instructions and created a OAuth2 Client.

I start both applications, visit 127.0.0.1:9999 to open a Client, client redirects me to localhost:8080/login, I enter user details and Authentication Provider redirects me to 127.0.0.1:9999/login and I get an error message:

Authentication Failed: Could not obtain user details from token

This is what gets logged:

INFO 2800 --- [nio-9999-exec-3] o.s.b.a.s.o.r.UserInfoTokenServices : Getting user info from: http:// localhost:8080/me

DEBUG 2800 --- [nio-9999-exec-3] o.s.s.oauth2.client.OAuth2RestTemplate : Created GET request for http:// localhost:8080/me

DEBUG 2800 --- [nio-9999-exec-3] o.s.s.oauth2.client.OAuth2RestTemplate : Setting request Accept header to [application/json, application/*+json]

DEBUG 2800 --- [nio-9999-exec-3] o.s.s.oauth2.client.OAuth2RestTemplate : GET request for http:// localhost:8080/me resulted in 200 (OK)

INFO 2800 --- [nio-9999-exec-3] o.s.b.a.s.o.r.UserInfoTokenServices : Could not fetch user details: class org.springframework.web.client.RestClientException, Could not extract response: no suitable HttpMessageConverter found for response type [interface java.util.Map] and content type [text/html;charset=UTF-8]]

This is my Client application:

@EnableAutoConfiguration
@Configuration
@EnableOAuth2Sso
@RestController
public class ClientApplication {
    
    @RequestMapping("/")
    public String home(Principal user) {
        return "Hello " + user.getName();
    }

    public static void main(String[] args) {
        SpringApplication.run(ClientApplication.class, args);
    }

}

This is client application YML:

server:
  port: 9999
security:
  oauth2:
    client:
      client-id: acme
      client-secret: acmesecret
      access-token-uri: http://localhost:8080/oauth/token
      user-authorization-uri: http://localhost:8080/oauth/authorize
    resource:
      user-info-uri: http://localhost:8080/me

This is my Authorization Provider application:

@SpringBootApplication
public class SecurityApp {

    public static void main(String[] args) {
        SpringApplication.run(SecurityApp.class, args);
    }

}

@Configuration
@EnableWebSecurity
@EnableAuthorizationServer
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER");
    }
}

@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/home").setViewName("home");
        registry.addViewController("/").setViewName("home");
        registry.addViewController("/hello").setViewName("hello");
        registry.addViewController("/login").setViewName("login");
    }

}

@RestController
public class Controller {

    @RequestMapping({ "/user", "/me" })
    public Map<String, String> user(Principal principal) {
      Map<String, String> map = new LinkedHashMap<>();
      map.put("name", principal.getName());
      return map;
    }
}

This is Application Provider YML:

security:
  oauth2:
    client:
      client-id: acme
      client-secret: acmesecret
      scope: read,write
      auto-approve-scopes: '.*'

Solution

  • I solved the issue! I was missing the Resource Server which handles the requests for user endpoint (user-info-uri). To the Authorization Provider application I added this class:

    @Configuration
    @EnableResourceServer
    public class ResourceServer
            extends ResourceServerConfigurerAdapter {
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                .antMatcher("/me")
                .authorizeRequests().anyRequest().authenticated();
        }
    }