title: How to generate a JWT access token with some custom claims in it?
body: <p>I'm trying to have my authorization server generate a JWT access token with some custom claims in it.</p>
  
  <p>Here is what the Bearer token returned by the authorization server <code>/auth/token</code> endpoint looks like: <code>51aea31c-6b57-4c80-9d19-a72e15cb2bb7</code></p>
  
  <p>I find this token a bit short to be a JWT token and to contain my custom claims...</p>
  
  <p>And when using it in subsequent requests to the resource server, it complains with the error: <code>Cannot convert access token to JSON</code></p>
  
  <p>I'm using the following dependencies:</p>
  
  <pre><code>  &lt;parent&gt;
      &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
      &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
      &lt;version&gt;2.1.1.RELEASE&lt;/version&gt;
      &lt;relativePath/&gt;
    &lt;/parent&gt;
  
    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework.security.oauth.boot&lt;/groupId&gt;
      &lt;artifactId&gt;spring-security-oauth2-autoconfigure&lt;/artifactId&gt;
      &lt;version&gt;2.1.2.RELEASE&lt;/version&gt;
    &lt;/dependency&gt;
  </code></pre>
  
  <p>The authorization server is configured this way:</p>
  
  <pre><code>@Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints
    .tokenServices(defaultTokenServices())
    .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
    .accessTokenConverter(jwtAccessTokenConverter())
    .userDetailsService(userDetailsService);
  
    endpoints
    .pathMapping("/oauth/token", RESTConstants.SLASH + DomainConstants.AUTH + RESTConstants.SLASH + DomainConstants.TOKEN);
  
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter()));
    endpoints
    .tokenStore(tokenStore())
    .tokenEnhancer(tokenEnhancerChain)
    .authenticationManager(authenticationManager);
  }
  
  @Bean
  @Primary
  public DefaultTokenServices defaultTokenServices() {
    DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
    defaultTokenServices.setTokenStore(tokenStore());
    defaultTokenServices.setSupportRefreshToken(true);
    return defaultTokenServices;
  }
  
  @Bean
  public TokenStore tokenStore() {
    return new JwtTokenStore(jwtAccessTokenConverter());
  }
  
  @Bean
  public JwtAccessTokenConverter jwtAccessTokenConverter() {
    JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
    jwtAccessTokenConverter.setKeyPair(new KeyStoreKeyFactory(new ClassPathResource(jwtProperties.getSslKeystoreFilename()), jwtProperties.getSslKeystorePassword().toCharArray()).getKeyPair(jwtProperties.getSslKeyPair()));
  return jwtAccessTokenConverter;
  }
  
  @Bean
  public TokenEnhancer tokenEnhancer() {
    return new CustomTokenEnhancer();
  }
  </code></pre>
  
  <p>And it's using the class:</p>
  
  <pre><code>class CustomTokenEnhancer implements TokenEnhancer {
  
    @Autowired
    private TokenAuthenticationService tokenAuthenticationService;
  
    // Add user information to the token
    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
      User user = (User) authentication.getPrincipal();
      Map&lt;String, Object&gt; info = new LinkedHashMap&lt;String, Object&gt;(accessToken.getAdditionalInformation());
      info.put(CommonConstants.JWT_CLAIM_USER_EMAIL, user.getEmail().getEmailAddress());
      info.put(CommonConstants.JWT_CLAIM_USER_FULLNAME, user.getFirstname() + " " + user.getLastname());
      info.put("scopes", authentication.getAuthorities().stream().map(s -&gt; s.toString()).collect(Collectors.toList()));
      info.put("organization", authentication.getName());
      DefaultOAuth2AccessToken customAccessToken = new DefaultOAuth2AccessToken(accessToken);
      customAccessToken.setAdditionalInformation(info);
      customAccessToken.setExpiration(tokenAuthenticationService.getExpirationDate());
      return customAccessToken;
    }
  
  }
  </code></pre>
  
  <p>I also have the class:</p>
  
  <pre><code>@Configuration
  class CustomOauth2RequestFactory extends DefaultOAuth2RequestFactory {
  
    @Autowired
    private TokenStore tokenStore;
  
    @Autowired
    private UserDetailsService userDetailsService;
  
    public CustomOauth2RequestFactory(ClientDetailsService clientDetailsService) {
      super(clientDetailsService);
    }
  
    @Override
    public TokenRequest createTokenRequest(Map&lt;String, String&gt; requestParameters, ClientDetails authenticatedClient) {
      if (requestParameters.get("grant_type").equals("refresh_token")) {
        OAuth2Authentication authentication = tokenStore
            .readAuthenticationForRefreshToken(tokenStore.readRefreshToken(requestParameters.get("refresh_token")));
        SecurityContextHolder.getContext()
            .setAuthentication(new UsernamePasswordAuthenticationToken(authentication.getName(), null,
                userDetailsService.loadUserByUsername(authentication.getName()).getAuthorities()));
      }
      return super.createTokenRequest(requestParameters, authenticatedClient);
    }
  
  }
  </code></pre>
  
  <p>UPDATE: I also tried the alternative way of specifying the custom claim:</p>
  
  <pre><code>@Component
  class CustomAccessTokenConverter extends JwtAccessTokenConverter {
  
      @Autowired
    private TokenAuthenticationService tokenAuthenticationService;
  
    @Override
    public OAuth2Authentication extractAuthentication(Map&lt;String, ?&gt; claims) {
      OAuth2Authentication authentication = super.extractAuthentication(claims);
      authentication.setDetails(claims);
      return authentication;
    }
  
    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
      User user = (User) authentication.getPrincipal();
      Map&lt;String, Object&gt; info = new LinkedHashMap&lt;String, Object&gt;(accessToken.getAdditionalInformation());
      info.put(CommonConstants.JWT_CLAIM_USER_EMAIL, user.getEmail().getEmailAddress());
      info.put(CommonConstants.JWT_CLAIM_USER_FULLNAME, user.getFirstname() + " " + user.getLastname());
      info.put("scopes", authentication.getAuthorities().stream().map(s -&gt; s.toString()).collect(Collectors.toList()));
      info.put("organization", authentication.getName());
      DefaultOAuth2AccessToken customAccessToken = new DefaultOAuth2AccessToken(accessToken);
      customAccessToken.setAdditionalInformation(info);
      customAccessToken.setExpiration(tokenAuthenticationService.getExpirationDate());
      return super.enhance(customAccessToken, authentication);
    }
  
  }
  </code></pre>
  
  <p>with it being called like:</p>
  
  <pre><code>endpoints
  .tokenStore(tokenStore())
  .tokenEnhancer(jwtAccessTokenConverter())
  .accessTokenConverter(jwtAccessTokenConverter())
  </code></pre>
  
  <p>but it changed nothing and the error remained identical.</p>
  
  <p>Running with the debugger, none of these two enhancer overrides are called.</p>