Extending Spring OAuth2 Token Validation to Populate Full User Details

This article explains how to customize the default OAuth2 check‑token flow in Spring Cloud by extending the token converter to assemble complete user information—including IDs, department and tenant data—directly into the security context, eliminating extra database queries and improving performance.

Java Architecture Diary
Java Architecture Diary
Java Architecture Diary
Extending Spring OAuth2 Token Validation to Populate Full User Details

User carries a token and requests a resource server.

Resource server interceptor forwards the token to the authentication server and uses TokenStore to validate the token.

After validation, the token only contains the username.

The resource server then calls UserDetailsService to fetch the full user information based on the username.

For detailed performance bottleneck analysis, refer to the previous article "Extending JWT to Solve OAuth2 Performance Bottlenecks". This article focuses on extending the traditional UUID‑token scenario to improve system throughput and resolve performance issues.

Default check‑token parsing logic

<ol>
<li><code>@Override</code></li>
<li><code>public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException {</code></li>
<li><code>    MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();</code></li>
<li><code>    formData.add(tokenName, accessToken);</code></li>
<li><code>    HttpHeaders headers = new HttpHeaders();</code></li>
<li><code>    headers.set("Authorization", getAuthorizationHeader(clientId, clientSecret));</code></li>
<li><code>    // Call authentication server's check‑token endpoint</code></li>
<li><code>    Map<String, Object> map = postForMap(checkTokenEndpointUrl, formData, headers);</code></li>
<li><code>    return tokenConverter.extractAuthentication(map);
}</code></li>
</ol>

After the authentication server returns the token information, the resource server assembles user details using only the username. If a custom UserDetailsService is configured, it performs an additional query to load the full user profile.

Problem analysis

The check‑token response contains all user information.

The resource server only extracts the username when building the security context.

When UserDetailsService is set, it triggers an extra database query.

Observed issues

If UserDetailsService is configured, the full user information becomes available in the Spring Security context; otherwise only the username is present.

The additional query introduces unnecessary performance overhead.

Solution

Extend UserAuthenticationConverter to parse the entire check‑token response and populate the Spring Security context with all user attributes.

/**
 * @author lengleng
 * @date 2019-03-07
 * <p>Convert check‑token result into user information</p>
 */
public class PigxUserAuthenticationConverter implements UserAuthenticationConverter {
    private static final String N_A = "N/A";

    @Override
    public Authentication extractAuthentication(Map<String, ?> map) {
        if (map.containsKey(USERNAME)) {
            Collection<? extends GrantedAuthority> authorities = getAuthorities(map);
            String username = (String) map.get(USERNAME);
            Integer id = (Integer) map.get(SecurityConstants.DETAILS_USER_ID);
            Integer deptId = (Integer) map.get(SecurityConstants.DETAILS_DEPT_ID);
            Integer tenantId = (Integer) map.get(SecurityConstants.DETAILS_TENANT_ID);
            PigxUser user = new PigxUser(id, deptId, tenantId, username, N_A, true);
            return new UsernamePasswordAuthenticationToken(user, N_A, authorities);
        }
        return null;
    }
}

Inject this implementation into RemoteTokenServices and configure the resource server:

public class PigxResourceServerConfigurerAdapter extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
        UserAuthenticationConverter userTokenConverter = new PigxUserAuthenticationConverter();
        accessTokenConverter.setUserTokenConverter(userTokenConverter);
        remoteTokenServices.setRestTemplate(lbRestTemplate);
        remoteTokenServices.setAccessTokenConverter(accessTokenConverter);
        resources.tokenServices(remoteTokenServices);
    }
}

After applying the extension, the flow diagram updates accordingly:

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaAuthenticationSpring CloudOAuth2Tokenspring-securityUserDetails
Java Architecture Diary
Written by

Java Architecture Diary

Committed to sharing original, high‑quality technical articles; no fluff or promotional content.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.