Issue
I have a REST service, written using Spring MVC. The server is an OAuth2 resource server and I am using the JwtAuthenticationProvider to have the JWT parsed and turned into the Principal. This all works fine.
However, what I really want to do is to load user details from a database, using the username provided from a Claim in the JWT. Then that new Principal should replace or (ideally) wrap the Jwt so that it is available directly from the SecurityContext.
I am really struggling to see how to do this. The JwtAuthenticationProvider does not seem to work with a UserDetailsService. I also looked at doing this with a Converter - but it is not easy to extend JwtAuthenticationConverter because the convert method is final (why?).
So to be very clear, here is what I ideally want to happen:
- Bearer token is presented to service.
- Parse Jwt and extract claims
- Use one of these claims as a key to my user database, where I can look up attributes, entitlements etc
- Turn these into a new Principal object which is available in the SecurityContext's Authentication object.
The configure method in my WebSecurityConfigurerAdapter has this:
http.authorizeRequests().antMatchers("/api/*").authenticated().and().oauth2ResourceServer().jwt();
I cannot be the only person who wants to use a user database along with OAuth2, so I must be missing something fundamental? I am using Spring Security 5.2.0.
Solution
The JwtAuthenticationProvider
does not support an UserDetailsService
because in theory you are not supposed to have UserDetails
in an application that does not manage credentials. I'm not saying that you cannot have any type of user, but the UserDetailsService
will not be used or autowired by Spring Security.
You could register a bean of type JwtAuthenticationConverter
, do whatever you need in the convert
method and return your custom authentication token, like so:
@Component
public class JwtAuthenticationConverterAdapter implements Converter<Jwt, AbstractAuthenticationToken> {
private JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
@Override
public AbstractAuthenticationToken convert(Jwt jwt) {
var token = this.jwtAuthenticationConverter.convert(jwt);
// build your custom token with the properties from the token above
return customToken;
}
}
Answered By - Marcus Hert da Coregio
Answer Checked By - Clifford M. (JavaFixing Volunteer)