How to Customize OAuth2 Tokens with Business Data in Spring Cloud

This article explains how to extend the default OAuth2 token response by adding business-related fields such as tenant, user, and department IDs, and walks through the relevant Spring Cloud source code that generates and enhances tokens for improved performance and security.

Java Architecture Diary
Java Architecture Diary
Java Architecture Diary
How to Customize OAuth2 Tokens with Business Data in Spring Cloud

Personalized Token Purpose

By default, the /oauth/token response includes access_token , token_type , refresh_token , expires_in , and scope , but it does not contain business information like user or tenant data.

{
    "access_token": "e6669cdf-b6cd-43fe-af5c-f91a65041382",
    "token_type": "bearer",
    "refresh_token": "da91294d-446c-4a89-bdcf-88aee15a75e8",
    "expires_in": 43199,
    "scope": "server"
}

The default token does not include user‑specific business information.

Extending the token to include fields such as tenant_id , license , dept_id , user_id , and username avoids repeated system calls and greatly improves performance.

{
    "access_token": "a6f3b6d6-93e6-4eb8-a97d-3ae72240a7b0",
    "token_type": "bearer",
    "refresh_token": "710ab162-a482-41cd-8bad-26456af38e4f",
    "expires_in": 42396,
    "scope": "server",
    "tenant_id": 1,
    "license": "made by pigx",
    "dept_id": 1,
    "user_id": 1,
    "username": "admin"
}

Password Grant Token Source Code Analysis

Reference diagram (red box).

ResourceOwnerPasswordTokenGranter authenticates the user request and obtains the current user context.

protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
    Map<String, String> parameters = new LinkedHashMap<String, String>(tokenRequest.getRequestParameters());
    String username = parameters.get("username");
    String password = parameters.get("password");
    // Protect from downstream leaks of password
    parameters.remove("password");
    Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password);
    ((AbstractAuthenticationToken) userAuth).setDetails(parameters);
    userAuth = authenticationManager.authenticate(userAuth);
    OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
    return new OAuth2Authentication(storedOAuth2Request, userAuth);
}

Then AbstractTokenGranter.getAccessToken() obtains an OAuth2AccessToken .

protected OAuth2AccessToken getAccessToken(ClientDetails client, TokenRequest tokenRequest) {
    return tokenServices.createAccessToken(getOAuth2Authentication(client, tokenRequest));
}

The default implementation uses DefaultTokenServices to create the token.

public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
    // ... series of checks (validity, expiration, etc.)
    OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
    tokenStore.storeAccessToken(accessToken, authentication);
    // In case it was modified
    refreshToken = accessToken.getRefreshToken();
    if (refreshToken != null) {
        tokenStore.storeRefreshToken(refreshToken, authentication);
    }
    return accessToken;
}

Core logic of createAccessToken defines default validity periods.

// default refresh token validity (30 days)
private int refreshTokenValiditySeconds = 60 * 60 * 24 * 30;
// default access token validity (12 hours)
private int accessTokenValiditySeconds = 60 * 60 * 12;

private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
    DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(uuid);
    token.setExpiration(Date);
    token.setRefreshToken(refreshToken);
    token.setScope(authentication.getOAuth2Request().getScope());
    return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;
}

After assembling the token object, the authentication server invokes a TokenEnhancer to enrich the default token.

TokenEnhancer.enhance adds personalized business fields from the user context.

public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
    final Map<String, Object> additionalInfo = new HashMap<>(8);
    PigxUser pigxUser = (PigxUser) authentication.getUserAuthentication().getPrincipal();
    additionalInfo.put("user_id", pigxUser.getId());
    additionalInfo.put("username", pigxUser.getUsername());
    additionalInfo.put("dept_id", pigxUser.getDeptId());
    additionalInfo.put("tenant_id", pigxUser.getTenantId());
    additionalInfo.put("license", SecurityConstants.PIGX_LICENSE);
    ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
    return accessToken;
}

Final Implementation Based on Pig

Pig is a Spring Cloud and OAuth2.0 based platform with a Vue front‑end, supporting account, SMS, SSO and other login methods, and provides video tutorials.

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.

BackendSecuritySpring CloudOAuth2Token
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.