I was having a lot of problems trying to switch from the InMemoryTokenStore to the JWTTokenStore while using the @AuthenticationPrincipal annotation for injecting the principal. The in-memory would inject the UserDetails, as expected, while the JWT store only injected the username.
I finally figured out how to fix this. It involved implementing a UserAuthenticationConverter that uses the UserDetailsService in the UserAuthenticationConverter#extractAuthentication method. It seems like this should be an option included in Spring OAuth to me. In addition to the existing DefaultUserAuthenticationConverter.
Also, to make it work like the DefaultUserAuthenticationConverter I had to replicate the DefaultUserAuthenticationConverter#getAuthorities() method. It is currently marked as private. Can I also suggest changing the visibility to protected and expose the defaultAuthorities. That makes it much easier to subclass DefaultUserAuthenticationConverter if necessary.
I don't like making private methods public, so you still have to write your own if you want to change it (but it's only a few lines to copy).
So I'm trying to figure out how this is used in practice. Since this setUserDetailsService() helper was added to DefaultUserAuthenticationConverter, I need to explicitly cast the AccessTokenConverter I get from jwtAccessTokenConverter.getAccessTokenConverter()? This implementation works for me, but I just wanted to check if this was "good practice":
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
// ...
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey("some_key");
((DefaultAccessTokenConverter) jwtAccessTokenConverter.getAccessTokenConverter())
.setUserTokenConverter(userAuthenticationConverter());
return jwtAccessTokenConverter;
}
@Bean
public UserAuthenticationConverter userAuthenticationConverter() {
DefaultUserAuthenticationConverter defaultUserAuthenticationConverter = new DefaultUserAuthenticationConverter();
defaultUserAuthenticationConverter.setUserDetailsService(userDetailsService);
return defaultUserAuthenticationConverter;
}
// ...
}
Most helpful comment
So I'm trying to figure out how this is used in practice. Since this
setUserDetailsService()helper was added toDefaultUserAuthenticationConverter, I need to explicitly cast theAccessTokenConverterI get fromjwtAccessTokenConverter.getAccessTokenConverter()? This implementation works for me, but I just wanted to check if this was "good practice":