How to add more data in access_token JWT
Your question is quite similar/same to below SO thread
Spring OAuth 2 + JWT Inlcuding additional info JUST in access token
I will just make it a bit easier to understand. There are two things
- A access token enhancer which enhances your token to include more information
- A token converter which converts the token to output you see in API
So what you want it is below
- Access token enhancer should see the additional properties
- Access token converter should not see the additional properties
Below is the class that I actually used
package org.baeldung.config;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfigJwt extends AuthorizationServerConfigurerAdapter {
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("sampleClientId")
.authorizedGrantTypes("implicit")
.scopes("read", "write", "foo", "bar")
.autoApprove(false)
.accessTokenValiditySeconds(3600)
.and()
.withClient("fooClientIdPassword")
.secret("secret")
.authorizedGrantTypes("password", "authorization_code", "refresh_token")
.scopes("foo", "read", "write")
.accessTokenValiditySeconds(3600)
// 1 hour
.refreshTokenValiditySeconds(2592000)
// 30 days
.and()
.withClient("barClientIdPassword")
.secret("secret")
.authorizedGrantTypes("password", "authorization_code", "refresh_token")
.scopes("bar", "read", "write")
.accessTokenValiditySeconds(3600)
// 1 hour
.refreshTokenValiditySeconds(2592000) // 30 days
;
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
@Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
final TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter()));
endpoints.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancerChain)
.authenticationManager(authenticationManager);
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter converter = new JwtAccessTokenConverter(){
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
if(authentication.getOAuth2Request().getGrantType().equalsIgnoreCase("password")) {
final Map<String, Object> additionalInfo = new HashMap<String, Object>();
additionalInfo.put("organization", authentication.getName() + randomAlphabetic(4));
((DefaultOAuth2AccessToken) accessToken)
.setAdditionalInformation(additionalInfo);
}
accessToken = super.enhance(accessToken, authentication);
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(new HashMap<>());
return accessToken;
}
};
// converter.setSigningKey("123");
final KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("mytest.jks"), "mypass".toCharArray());
converter.setKeyPair(keyStoreKeyFactory.getKeyPair("mytest"));
return converter;
}
// @Bean
// public TokenEnhancer tokenEnhancer() {
// return new CustomTokenEnhancer();
// }
}
The original code is on below
https://github.com/Baeldung/spring-security-oauth
Doesn't include my changes though, but above code is enough
Testing
As you can see body doesn't contain the additional properties
As you can see the access token has the additional properties. Also your requirement for only grant_type
as password
is met through
if(authentication.getOAuth2Request().getGrantType().equalsIgnoreCase("password")) {
Eniss
Updated on June 07, 2022Comments
-
Eniss almost 2 years
I am trying to add new fields in JWT token which is actually
access_token
which is generated withgrant_type=password
. I want to add more fields if grant type is onlypassword
.If I implement a custom token enhancer, it adds new fields in the response body of oauth login api. But I only need those new fields inside
access_token
JWT.e.g.:
when decoding
access_token
, Object should be from{ "user_name": "uuid", "scope": [ "trust" ], "exp": 1522008499, "authorities": [ "USER" ], "jti": "9d827f63-99ba-4fc1-a838-bc74331cf660", "client_id": "myClient" }
to
{ "user_name": "uuid", "newField": [ { "newFieldChild": "1", }, { "newFieldChild": "2", } ], "scope": [ "trust" ], "exp": 1522008499, "authorities": [ "USER" ], "jti": "9d827f63-99ba-4fc1-a838-bc74331cf660", "client_id": "myClient" }
Implementing
CustomTokenEnhancer
addsnewField
list in the response body of login:{ "access_token": "jwt-access_token", "token_type": "bearer", "refresh_token": "jwt-refresh_token", "expires_in": 299999, "scope": "trust", "jti": "b23affb3-39d3-408a-bedb-132g6de15d7", "newField": [ { "newFieldChild": "1", }, { "newFieldChild": "2", } ] }
CustomTokenEnhancer
:public class CustomTokenEnhancer implements TokenEnhancer { @Override public OAuth2AccessToken enhance( OAuth2AccessToken accessToken, OAuth2Authentication authentication) { Map<String, Object> additionalInfo = new HashMap<>(); Map<String, String> newFields = ....; additionalInfo.put("newField", newFields); ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); return accessToken; } }
is it possible to modify
access_token
JWT ifgrant_type
ispassword
?