graphql-java-generator / graphql-maven-plugin-project

graphql-maven-plugin is a Maven Plugin for GraphQL, based on graphql-java. It accelerates the development for both the client and the server, by generating the Java code. It allows a quicker development when in contract-first approach, by avoiding to code the boilerplate code.
https://graphql-maven-plugin-project.graphql-java-generator.com
MIT License
115 stars 47 forks source link

Allowing Authorization Token in Connection_Init payload for subscription #185

Closed bhowmikdebarshi closed 1 year ago

bhowmikdebarshi commented 1 year ago

Hi

Currently we are allowing to pass the token in header while establishing the subscription channel. Can we allow it in connection_init payload though some sort of interceptor?
https://docs.spring.io/spring-graphql/docs/current-SNAPSHOT/reference/html/#client.websocketgraphqlclient.interceptor

Thanks

etienne-sf commented 1 year ago

Which version of the plug-in are you using? For a client or a server?

If you're using a 1.x version, the no, there is no easy way. But you can change the runtime, for instance by copying it into your project, and change its behavior. Of course, you would then have to do it again each time you upgrade the plug-in.

As you're pointing out the spring-GraphQL doc, I guess you switched to the 2.0Rc1.

Then I don't know. But if spring-graphql allows it, juste do it. You'll have to check their doc.

Étienne

bhowmikdebarshi commented 1 year ago

I'm using gradle plugin 1.18.11.

Right, I don't want to maintain all those changes while upgrading the plugin. I'll play with 2.0RC1 and see if its easy to implement those interceptor.

etienne-sf commented 1 year ago

Please let me know what you've found (or will find) :

etienne-sf commented 1 year ago

Any news ?

bhowmikdebarshi commented 1 year ago

Hi, Sorry for late response.

yes spring-graphql allows it. We need to override the bean creation for GraphQlClient to use this interceptor.

 GraphQlClient webSocketGraphQlClient(ServerOAuth2AuthorizedClientExchangeFilterFunction oAuth) {
       SubscriptionInterceptor interceptor = new SubscriptionInterceptor(oAuth);
        WebSocketClient client = new ReactorNettyWebSocketClient();
        return WebSocketGraphQlClient.builder(graphqlSubscriptionUrl, client)
                .interceptor(interceptor)
                .build();
    }

This is interceptor class -


import lombok.extern.slf4j.Slf4j;
import org.springframework.graphql.client.ClientGraphQlRequest;
import org.springframework.graphql.client.ClientGraphQlResponse;
import org.springframework.graphql.client.WebSocketGraphQlClientInterceptor;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

@Slf4j
public class SubscriptionInterceptor implements WebSocketGraphQlClientInterceptor {

    ServerOAuth2AuthorizedClientExchangeFilterFunction serverOAuth2AuthorizedClientExchangeFilterFunction;

    SubscriptionInterceptor(ServerOAuth2AuthorizedClientExchangeFilterFunction oAuth){
        this.serverOAuth2AuthorizedClientExchangeFilterFunction = oAuth;
    }

    @Override
    public Mono<Object> connectionInitPayload() {
        log.debug("Adding token to connection init payload");
        OAuthTokenExtractor oAuthTokenExtractor = new OAuthTokenExtractor(serverOAuth2AuthorizedClientExchangeFilterFunction);
        return oAuthTokenExtractor.getAuthorizationHeaderValue().map(token -> {
            Map map = new HashMap();
            map.put("authorization", token);
            return map;
        });
    }

    @Override
    public Mono<Void> handleConnectionAck(Map<String, Object> ackPayload) {
        log.debug("Connection acknowledged");
        return Mono.empty();
    }

    @Override
    public Flux<ClientGraphQlResponse> interceptSubscription(ClientGraphQlRequest request, SubscriptionChain chain) {
        return chain.next(request);
    }

}
bhowmikdebarshi commented 1 year ago

Since 2.0 uses Spring client underneath, its pretty easy to use custom interceptor to intercept the connection init call and pass the auth token in payload.