'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 |