When using Spring authorization server, it’s very convenient that the server can generate access tokens (JWTs) automatically so developers do not have to write boilerplate code. The generated access tokens contain standard claims such as subject (sub), audience (aud), issuer (iss), issued at (iat), etc - something like this:
{ "sub": "client-1", "aud": "client-1", "nbf": 1742567096, "iss": "http://localhost:8080", "exp": 1742567396, "iat": 1742567096, "jti": "a58fe6d5-9956-4a2c-beb4-795aedfbdccf" }
What if we want to modify something, such as using issuer name instead of URL, adding scope/authority information, or removing the audience claim?
Spring authorization server allows us to customize the generated access tokens by configuring a OAuth2TokenCustomizer bean. In this post, I’d like to share with you some code examples for customizing access tokens generated by Spring authorization server, including add, update and remove claims.
To do that, declare a bean of type OAuth2TokenCustomizer in the authorization server configuration class as follows:
@Configuration public class AuthorizationServerConfig { @Bean SecurityFilterChain authorizationServerFilterChain(HttpSecurity http) throws Exception { ... } @Bean RegisteredClientRepository registeredClientRepository() { ... } @Bean OAuth2TokenCustomizer<JwtEncodingContext> tokenCustomizer() { return (context) -> { if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) { // code to modify claims in the generated access tokens goes here } }; } }
Here, the context variable is of type JwtEncodingContext. And the additional import statements are:
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer; import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
Next, let’s see how to update, add and remove claims in the generated access tokens.
To set custom values for predefined claim names (id, subject, issuer, issued at, not before, …), we can use the JwtClaimsSet.Builder object that is obtained from the JwtEncodingContext’s getClaims() method:
Builder builder = context.getClaims();
Then use one of the following methods:
For example, the following code examples illustrates how to set a custom issuer name and longer expiration time:
@Bean OAuth2TokenCustomizer<JwtEncodingContext> tokenCustomizer() { return (context) -> { if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) { Builder builder = context.getClaims(); builder.issuer("CodeJava"); builder.expiresAt(Instant.now().plus(30, ChronoUnit.MINUTES)); } }; }
Decode the generated JWT, you can see the values of the iss and exp claims get updated:
{ "sub": "client-1", "aud": "client-1", "nbf": 1742611022, "iss": "CodeJava", "exp": 1742612822, "iat": 1742611022, "jti": "f9432247-7dda-4a30-830e-2bf37753f872" }
You can also use the Builder.claim(name, value) method to set value for any claim. For example:
builder.claim("iss", "CodeJava.net");
Next, let’s see how to add custom claims to the generated JWTs.
As mentioned above, we can use the Builder.claim(name, value) method to add custom claims to the generated access tokens. For example, the following code adds non-standard claims named scope and name to the JWTs:
@Bean OAuth2TokenCustomizer<JwtEncodingContext> tokenCustomizer() { return (context) -> { if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) { RegisteredClient client = context.getRegisteredClient(); Builder builder = context.getClaims(); builder.claim("scope", client.getScopes()); builder.claim("name", client.getClientName()); } }; }
The generated JWT will be updated accordingly, for example:
{ ... "scope": [ "read" ], "name": "John Doe", ... }
It’s easy and convenient, isn’t it?
To remove one or more claims from the generated access tokens, we need to obtain a Map of claim set and use the remove() method. For example, the following code snippet removes the claims audience (aud) and not before (nbf) from the generated JWTs:
@Bean OAuth2TokenCustomizer<JwtEncodingContext> tokenCustomizer() { return (context) -> { if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) { Builder builder = context.getClaims(); builder.claims((claims) -> { claims.remove("aud"); claims.remove("nbf"); }); } }; }
That’s my share about customizing the access tokens (JWTs) generated by Spring authorization server. You can update, add or remove claims as you wish via the configuration of an OAuth2TokenCustomizer bean.
To see the coding in action, watch the following video: