can I include user information while issuing an access token?
You will need to implement a custom TokenEnhancer like so:
public class CustomTokenEnhancer implements TokenEnhancer { @Override public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { User user = (User) authentication.getPrincipal(); final Map<String, Object> additionalInfo = new HashMap<>(); additionalInfo.put("customInfo", "some_stuff_here"); additionalInfo.put("authorities", user.getAuthorities()); ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); return accessToken; }}
and add it to your AuthorizationServerConfigurerAdapter as a bean with the corresponding setters
@Configuration@EnableAuthorizationServerprotected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { // Some autowired stuff here @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { // @formatter:off endpoints // ... .tokenEnhancer(tokenEnhancer()); // @formatter:on } @Bean @Primary public AuthorizationServerTokenServices tokenServices() { DefaultTokenServices tokenServices = new DefaultTokenServices(); // ... tokenServices.setTokenEnhancer(tokenEnhancer()); return tokenServices; } // Some @Bean here like tokenStore @Bean public TokenEnhancer tokenEnhancer() { return new CustomTokenEnhancer(); }}
then in a controller (for example)
@RestControllerpublic class MyController { @Autowired private AuthorizationServerTokenServices tokenServices; @RequestMapping(value = "/getSomething", method = RequestMethod.GET) public String getSection(OAuth2Authentication authentication) { Map<String, Object> additionalInfo = tokenServices.getAccessToken(authentication).getAdditionalInformation(); String customInfo = (String) additionalInfo.get("customInfo"); Collection<? extends GrantedAuthority> authorities = (Collection<? extends GrantedAuthority>) additionalInfo.get("authorities"); // Play with authorities return customInfo; }}
I'm personnaly using a JDBC TokenStore so my "Some autowired stuff here" are corresponding to some @Autowired Datasource, PasswordEncoder and what not.
Hope this helped!
If you are using Spring's JwtAccessTokenConverter
or DefaultAccessTokenConverter
you can add your custom CustomTokenEnhancer (see first response) and apply it using a TokenEnhancerChain like this:
@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { TokenEnhancerChain enhancerChain = new TokenEnhancerChain(); enhancerChain.setTokenEnhancers(Arrays.asList(customTokenEnhancer(), accessTokenConverter())); endpoints.tokenStore(tokenStore()) .tokenEnhancer(enhancerChain) .authenticationManager(authenticationManager);}@Beanprotected JwtAccessTokenConverter jwtTokenEnhancer() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("my_signing_key"); return converter;}@Bean public TokenEnhancer customTokenEnhancer() { return new CustomTokenEnhancer();}
Another solution is to create a custom TokenConverter that extends Spring's JwtAccessTokenConverter
and override the enhance() method with your custom claims.
public class CustomTokenConverter extends JwtAccessTokenConverter {@Overridepublic OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { final Map<String, Object> additionalInfo = new HashMap<>(); additionalInfo.put("customized", "true"); User user = (User) authentication.getPrincipal(); additionalInfo.put("isAdmin", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()).contains("BASF_ADMIN")); ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); return super.enhance(accessToken, authentication); }}
And then:
@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(tokenStore()) .tokenEnhancer(customTokenEnhancer()) .authenticationManager(authenticationManager);}@Bean public CustomTokenConverter customTokenEnhancer() { return new CustomTokenConverter();}
Together with:
@Beanpublic TokenEnhancer tokenEnhancer() { return new CustomTokenEnhancer();}
You have to include
@Beanpublic DefaultAccessTokenConverter accessTokenConverter() { return new DefaultAccessTokenConverter();}
and add everything to endpoints config:
@Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenStore(tokenStore) .tokenEnhancer(tokenEnhancer()) .accessTokenConverter(accessTokenConverter()) .authorizationCodeServices(codeServices) .authenticationManager(authenticationManager) ; }
Without it, your CustomTokenEnhancer will not work.