Search code examples
spring-bootspring-securityjwtspring-security-oauth2

Spring security can't extract roles from JWT


im using FusionAuth for my Oauth server and I have a problem. Spring security will decode the JWT successfully but there are no roles!

This is my complete Authentication Object in JSON:

https://jsoneditoronline.org/#left=cloud.911cb58e717544ab9168632ed221aae1

and as you can see I have the roles and the role object in my principal. but when I try to use it in @PreAuthroize or even log it. it's empty.

WebSecurityConfigurerAdapter:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests(authorizeRequests ->
                        authorizeRequests
                                .antMatchers(HttpMethod.GET, "v1/balance/**").permitAll()
                                .antMatchers(HttpMethod.POST, "v1/balance/**").permitAll()
                                .antMatchers(HttpMethod.GET, "/actuator/**").permitAll()
                                .anyRequest().authenticated()
                )
                .oauth2ResourceServer(oauth2ResourceServer ->
                        oauth2ResourceServer
                                .jwt(jwt ->
                                        jwt.decoder(JwtDecoders.fromIssuerLocation(issuerUri)).jwkSetUri(jwksUrl)
                                )
                );

    }

this is how i try to log the roles:

      @GetMapping("/currency/{currency}")
//    @PreAuthorize("hasAnyRole('admin')")
    public CurrencyBalance getWalletByCurrency(@PathVariable String currency, Principal principal){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        Set<String> roles = authentication.getAuthorities().stream()
                .map(r -> r.getAuthority()).collect(Collectors.toSet());
        System.out.println(roles);
        System.out.println(new Gson().toJson(authentication));
        System.out.println(authentication.getAuthorities());
        System.out.println(authentication.getCredentials().toString());
        System.out.println(authentication.getDetails());
        System.out.println(authentication.getPrincipal());
        System.out.println(authentication.getName());
        return null;
//        return balanceService.getWalletByCurrency(principal.getName(),currency);
    }

Solution

  • First of all, you need to understand How JWT Authentication Works spring security jwt
    (source: spring.io)

    JwtAuthenticationConverter converts JWT to authorities of Authentication, By default it only decode the SCOPE of JWT to authorities.(look at JwtGrantedAuthoritiesConverter).

    You have to create a subclass of JwtAuthenticationConverter and override the extractAuthorities method if you want to decode custom attribute of JWT. Finally, declare you custom subclass as a Bean, spring security will automatically use it