I have a Spring WebFlux application and am trying to write a WebGraphQlInterceptor to enforce authorization. The authorization requires access to HTTP headers and GraphQL variables, both of which are easily accessible from a WebGraphQlInterceptor. However, if the request fails authorization, I do not want to execute the controller handler and instead exit early with an error response. I have the custom error response working OK, but I cannot figure out how to bypass the controller -- it seems like I'm required to proceed down the original chain, execute the controller, and only then return the error response.
I'm hoping there's an easy solution I'm missing. The documentation seems sparse on this topic with very few examples online. The WebGraphQlInterceptor documentation lists some methods like apply() that sound like they might be helpful for altering the chain, but it's not clear how to use them. The interceptor interface requires a WebGraphQlResponse to be returned, and I can't find a way to return it without continuing down the original chain with chain.next(request) below:
@Override
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
return chain.next(request).map(response -> {
// Custom logic...
});
}
I also tried constructing my own custom WebGraphQlResponse from scratch to return from the interceptor, but this felt like a hack and a lot of unnecessary overhead.
I don't want the controller to be executed at all if authorization fails. Is this even possible with the WebGraphQlInterceptor? And what would the simplest implementation look like?
P.S. The WebFilter doesn't help me here because I need easy access to GraphQL variables, which isn't possible with WebFilters.
I found a workaround that involves an extra piece.
I made my WebGraphQlInterceptor pass the HTTP authorization headers to the GraphQL context, where it’s then accessible via FieldValidation GraphQL instrumentation. The FieldValidation GraphQL instrumentation runs later in the chain, after the GraphQL body has been parsed, so it has easy access to GraphQL variables. It also has access to original HTTP header values since the interceptor passed those via the GraphQL context. Then, based on whether the user is authorized or not, I made the field instrumentation return either a GraphQLError or an empty error list. If it returns an error, the framework correctly bypasses the controller and returns the error to the client.
Here's a relevant post in the spring-graphql GitHub: https://github.com/spring-projects/spring-graphql/issues/529#issuecomment-1310194130
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With