'How to get claims from jwt token in spring webflux
I am having a spring webflux based GraphQL application. The application is configured as resourceServer and I am able to access the /graphql endpoint by passing JWT token.
Within the JWT token there are claims that I want to access. I am trying to use the ReactiveSecurityContextHolder.getContext() but getting null every time.
ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.map(Authentication::getPrincipal)
.cast(Jwt.class)
The above code is in the GraphqlQueryResolver class. For graphql I are using the below dependency.
<dependency>
    <groupId>com.graphql-java-kickstart</groupId>
    <artifactId>graphql-spring-boot-starter</artifactId>
    <version>12.0.0</version>
</dependency>
Below is the security configuration.
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfig {
    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        return http
                .csrf(spec -> spec.disable())
                .authorizeExchange().pathMatchers("/api/**").permitAll()
                .anyExchange().authenticated().and()
                .oauth2Login()
                .and()
                .oauth2ResourceServer()
                .jwt().and().and().build();
    }
}
Now I am getting a UUID as part of the access token claim which I want to access on my graphql resolver class. But every time I try to get the JWT using the above code I am getting null.
If I try to get the same in @RestController with @AutheticationPrincipal it works perfectly. But I want to access the same using the SecurityContext in graphql resolver class.
Here is a simple resolver
public class CustomerResolver implements GraphQLQueryResolver {
    public Mono<String> getCustomerById (){
        return ReactiveSecurityContextHolder.getContext()
                .map(ctx -> ctx.getAuthentication())
                .map(authentication -> {
                    if(authentication instanceof OAuth2AuthenticationToken){
                        return ((OAuth2AuthenticationToken) authentication).getPrincipal().getAttributes();
                    } else if(authentication instanceof JwtAuthenticationToken){
                        return ((JwtAuthenticationToken) authentication).getTokenAttributes();
                    }
                    return null;
                }).map(jwt -> String.valueOf(jwt));
    }
}
And the corresponding schema file for graphql
type Query {
    getCustomerById: String
}
							
						Solution 1:[1]
Try to create minimal example to isolate the issue. The following worked for me with your security configuration but without Okta.configureResourceServer401ResponseBody(http);
@Configuration
@RestController
public class RouteConfig {
    @GetMapping(value = "/api/test")
    public Mono<String> test() {
        return ReactiveSecurityContextHolder.getContext()
                .map(ctx -> ctx.getAuthentication().getPrincipal())
                .cast(Jwt.class)
                .map(jwt -> jwt.getClaimAsString("tenant"));
    }
}
Here is a test using org.springframework.security:spring-security-test
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
class RouteConfigTest {
    @Autowired
    private WebTestClient client;
    @Test
    void test() {
        this.client.mutateWith(jwt())
                .get()
                .uri("/api/test")
                .accept(MediaType.APPLICATION_JSON)
                .exchange()
                .expectStatus().isOk()
                .expectBody(String.class).isEqualTo("company");
    }
    private static SecurityMockServerConfigurers.JwtMutator jwt() {
        return mockJwt()
                .jwt(jwt -> jwt.claim("tenant", "company"));
    }
}
    					Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|---|
| Solution 1 | Alex | 
