9

I'm building an OAuth2 authorization server based on the experimental Spring project Spring Authorization Server

My use case is quite simple, fetch users from a DB, and based on some properties of the user, set some custom claims in the JWT being produced. I haven't found a way to do so with Spring Authorization Server, the only way I could work out is to inject a jwtCustomizer object as part of the JwtEncoder bean definition:

  @Bean
  public JwtEncoder jwtEncoder(CryptoKeySource keySource) {
    NimbusJwsEncoder jwtEncoder = new NimbusJwsEncoder(keySource);
    jwtEncoder.setJwtCustomizer((headersBuilder, claimsBuilder) -> {
      // Inject some headers and claims...
    });
    return jwtEncoder;
  }

This obviously doesn't give me access to users information, therefore I can't set the claims I need at this point. Did anyone manage to solve this problem?

Nick Melis
  • 403
  • 1
  • 7
  • 19
  • You can set claims when you build `UserDetails` object, in Spring's `UserDetailsService::loadUserByUsername` that you implement – Nikolai Shevchenko Jan 14 '21 at 09:57
  • No you can't, I've tried that. You can set roles and authorities in `UserDetailsService::loadUserByName` but none of the roles and authorities you set ends up in the JWT – Nick Melis Jan 14 '21 at 13:13

2 Answers2

17

The solution for this is in a test of the library

    @Bean
    OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
        return context -> {
            if (context.getTokenType().getValue().equals(OidcParameterNames.ID_TOKEN)) {
                Authentication principal = context.getPrincipal();
                Set<String> authorities = principal.getAuthorities().stream()
                        .map(GrantedAuthority::getAuthority)
                        .collect(Collectors.toSet());
                context.getClaims().claim(AUTHORITIES_CLAIM, authorities);
            }
        };
    }
  • Above bean is setting authorities to the claim but the default NimbusJwsEncoder ignores authorities claim while building jwt. – VinothNair Jul 11 '22 at 11:35
0

You can try following way. Though it is Kotlin code, not Java, but approach should be clear:

import org.springframework.security.oauth2.provider.token.TokenEnhancer

class UserTokenEnhancer : TokenEnhancer {
    
    override fun enhance(accessToken: OAuth2AccessToken,
                         authentication: OAuth2Authentication): OAuth2AccessToken {

        val username = authentication.userAuthentication.name
        val additionalInfo = mapOf( /* populate with some data for given username */ )

        (accessToken as DefaultOAuth2AccessToken).additionalInformation = additionalInfo
        return accessToken
    }
}

Then just register bean:

@Bean
fun userTokenEnhancer(): TokenEnhancer {
    return UserTokenEnhancer()
}
Nikolai Shevchenko
  • 7,083
  • 8
  • 33
  • 42
  • 3
    TokenEnhancer is not available in Spring Security 5, which seems to be what the project spring-authorization-server is based on. So no, this solution does not apply to my specific case. – Nick Melis Jan 15 '21 at 12:19