Custom Userinfo in spring boot resource server

Share on:

Spring Resource Server

When implementing a standalone Resource Application server, we do not store any information related to user. We heavily rely on third party auth service providers to give such information on user's consent and update it.

This can give rise to implement OncePerRequestFilter where in we get bearer token in header and process plenty of information to read/write on db or calling userinfo api from auth server. Say for example, in sub key you are getting only id or usually a username field, what resource server usually do is validate this user_token by

  • calling userinfo api bad and slow way
  • validating using public key(cached or dynamic - this requires jwks endpoint on auth server to work)

Imagine you are stuck where private claims are not added and you server need those information. In such cases spring's Authention#getPrincipal returns only the sub key returned by auth server which is not sufficient, instead you want an user object in your controllers.

So in this case, i would extend DefaultUserAuthenticationConverter and fill my principal object to the user details i have in my database. Ofcource for meanigful user details i need to expose an endpoint on my resource server for an oauth user to update his extra details.

 

Implementation

 1
 2public class CustomUserAuthenticationConverter extends DefaultUserAuthenticationConverter {
 3
 4    private UserService userService;
 5
 6    CustomUserAuthenticationConverter(UserService userService) {
 7        this.userService = userService;
 8    }
 9
10    @Override
11    public Authentication extractAuthentication(Map<String, ?> map) {
12        Authentication authentication = super.extractAuthentication(map);
13        User oneByUsername = userService.findOneByUsername(authentication.getName());
14        if (oneByUsername != null) {
15            oneByUsername.setAuthorities((List<? extends GrantedAuthority>) authentication.getAuthorities());
16            System.out.println(oneByUsername.getUsername());
17            return new UsernamePasswordAuthenticationToken(oneByUsername,
18                    authentication.getCredentials(), authentication.getAuthorities());
19        } else {
20            throw new OAuth2AccessDeniedException("Full authentication is required");
21        }
22
23    }
24
25}

 

Usage

 1
 2//Slightly modified code
 3@EnableResourceServer
 4public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
 5
 6    private final UserService userService;
 7
 8    @Autowired
 9    public OAuth2ResourceSecurityConfig(UserService userService) {
10        this.userService = userService;
11    }
12
13    ...
14
15    @Override
16    public void configure(ResourceServerSecurityConfigurer config) throws Exception {
17        config.tokenServices(defaultTokenServices);
18    }
19
20
21    @Bean
22    @Primary
23    public DefaultTokenServices defaultTokenServices() {
24        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
25        defaultTokenServices.setTokenStore(tokenStore());
26        defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter(;
27        return defaultTokenServices;
28    }
29
30    private TokenStore tokenStore() {
31        return new JwtTokenStore(jwtAccessTokenConverter());
32    }
33
34    
35    private String publicKey() {
36        Resource resource = new ClassPathResource("public.txt");
37        String publicKey = null;
38        try {
39            publicKey = IOUtils.toString(resource.getInputStream());
40        } catch (final IOException e) {
41            log.error("Pub key error");
42            throw new RuntimeException(e);
43        }
44        return publicKey;
45    }
46
47
48    private JwtAccessTokenConverter jwtAccessTokenConverter() {
49        final DefaultAccessTokenConverter defaultConverter = new DefaultAccessTokenConverter();
50        //This is the actual usage
51        defaultConverter.setUserTokenConverter(new CustomUserAuthenticationConverter(userService));
52        final JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
53        jwtAccessTokenConverter.setVerifierKey(publicKey());
54        jwtAccessTokenConverter.setAccessTokenConverter(defaultConverter);
55        return jwtAccessTokenConverter;
56    }
57
58    @Bean
59    public CorsConfigurationSource corsConfigurationSource() {
60        CorsConfiguration configuration = new CorsConfiguration();
61        ...
62        return source;
63    }
64
65    @Bean
66    public FilterRegistrationBean corsFilter() {
67        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(corsConfigurationSource()));
68        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
69        return bean;
70    }
71
72
73}

Spring Provides powerful and customizable API for OAuth2 🕵️‍♂️

comments powered by Disqus