Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GraphQL authenticated subscription #20092

Closed
SLedunois opened this issue Sep 13, 2021 · 20 comments · Fixed by #36961
Closed

GraphQL authenticated subscription #20092

SLedunois opened this issue Sep 13, 2021 · 20 comments · Fixed by #36961
Labels
area/graphql area/smallrye env/windows Impacts Windows machines kind/bug Something isn't working
Milestone

Comments

@SLedunois
Copy link

Describe the bug

Using a subscription behind an authentication system produces a DataFetchingException like :

 Exception while fetching data (/monitorStatusChanges) : null: javax.enterprise.context.ContextNotActiveException
        at io.quarkus.arc.impl.ClientProxies.getDelegate(ClientProxies.java:40)
        at io.quarkus.security.runtime.SecurityIdentityProxy_ClientProxy.arc$delegate(SecurityIdentityProxy_ClientProxy.zig:42)
        at io.quarkus.security.runtime.SecurityIdentityProxy_ClientProxy.isAnonymous(SecurityIdentityProxy_ClientProxy.zig:99)
        at io.quarkus.security.runtime.interceptor.check.AuthenticatedCheck.apply(AuthenticatedCheck.java:17)
        at io.quarkus.security.runtime.interceptor.SecurityConstrainer.check(SecurityConstrainer.java:27)
        at io.quarkus.security.runtime.interceptor.SecurityHandler.handle(SecurityHandler.java:23)

Like this class (https://github.com/SLedunois/authenticated-graphql/blob/master/src/main/java/fr/sledunois/AuthenticatedGraphql.java) Graphql allow queries and mutation behind an authentication mechanism. Opening a subscription accept the websocket. However, it seems that security handler rejects the security context during subscription initialization :
image

Expected behavior

Subscription should works fine with authentication system.

Actual behavior

Opening a subscription workflow:

  1. Open a websocket, the server accept it and switch protocol;
  2. Subscription initialization send event to the server: {"query":"subscription userCreated{\n userCreated{\n id\n }\n}","variables":null,"operationName":"userCreated"}
  3. Serveur respond with: {"errors":[{"message":"Exception while fetching data (/userCreated) : null","locations":[{"line":2,"column":3}],"path":["userCreated"],"extensions":{"classification":"DataFetchingException"}}],"data":null}

Server throws the following exception:

2021-09-13 14:16:40,632 WARN  [not.gra.exe.SimpleDataFetcherExceptionHandler] (vert.x-eventloop-thread-7) Exception while fetching data (/userCreated) : null: javax.enterprise.context.ContextNotActiveException
        at io.quarkus.arc.impl.ClientProxies.getDelegate(ClientProxies.java:40)
        at io.quarkus.security.runtime.SecurityIdentityProxy_ClientProxy.arc$delegate(SecurityIdentityProxy_ClientProxy.zig:42)
        at io.quarkus.security.runtime.SecurityIdentityProxy_ClientProxy.isAnonymous(SecurityIdentityProxy_ClientProxy.zig:99)
        at io.quarkus.security.runtime.interceptor.check.AuthenticatedCheck.apply(AuthenticatedCheck.java:27)
        at io.quarkus.security.runtime.interceptor.SecurityConstrainer.check(SecurityConstrainer.java:28)
        at io.quarkus.security.runtime.interceptor.SecurityConstrainer_Subclass.check$$superforward1(SecurityConstrainer_Subclass.zig:100)
        at io.quarkus.security.runtime.interceptor.SecurityConstrainer_Subclass$$function$$1.apply(SecurityConstrainer_Subclass$$function$$1.zig:41)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
        at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:62)
        at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:51)
        at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(InvocationInterceptor_Bean.zig:521)
        at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
        at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
        at io.quarkus.security.runtime.interceptor.SecurityConstrainer_Subclass.check(SecurityConstrainer_Subclass.zig:170)
        at io.quarkus.security.runtime.interceptor.SecurityHandler.handle(SecurityHandler.java:23)
        at io.quarkus.security.runtime.interceptor.SecurityHandler_Subclass.handle$$superforward1(SecurityHandler_Subclass.zig:137)
        at io.quarkus.security.runtime.interceptor.SecurityHandler_Subclass$$function$$2.apply(SecurityHandler_Subclass$$function$$2.zig:33)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
        at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:62)
        at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:51)
        at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(InvocationInterceptor_Bean.zig:521)
        at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
        at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
        at io.quarkus.security.runtime.interceptor.SecurityHandler_Subclass.handle(SecurityHandler_Subclass.zig:296)
        at io.quarkus.security.runtime.interceptor.AuthenticatedInterceptor.intercept(AuthenticatedInterceptor.java:29)
        at io.quarkus.security.runtime.interceptor.AuthenticatedInterceptor_Bean.intercept(AuthenticatedInterceptor_Bean.zig:378)
        at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
        at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
        at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
        at fr.sledunois.AuthenticatedGraphql_Subclass.userCreated(AuthenticatedGraphql_Subclass.zig:279)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at io.smallrye.graphql.execution.datafetcher.helper.ReflectionHelper.invoke(ReflectionHelper.java:84)
        at io.smallrye.graphql.execution.datafetcher.MultiDataFetcher.invokeAndTransform(MultiDataFetcher.java:42)
        at io.smallrye.graphql.execution.datafetcher.AbstractDataFetcher.get(AbstractDataFetcher.java:53)
        at graphql.execution.instrumentation.dataloader.DataLoaderDispatcherInstrumentation.lambda$instrumentDataFetcher$0(DataLoaderDispatcherInstrumentation.java:87)
        at graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:279)
        at graphql.execution.SubscriptionExecutionStrategy.createSourceEventStream(SubscriptionExecutionStrategy.java:91)
        at graphql.execution.SubscriptionExecutionStrategy.execute(SubscriptionExecutionStrategy.java:53)
        at graphql.execution.Execution.executeOperation(Execution.java:159)
        at graphql.execution.Execution.execute(Execution.java:105)
        at graphql.GraphQL.execute(GraphQL.java:613)
        at graphql.GraphQL.parseValidateAndExecute(GraphQL.java:538)
        at graphql.GraphQL.executeAsync(GraphQL.java:502)
        at graphql.GraphQL.execute(GraphQL.java:433)
        at io.smallrye.graphql.execution.ExecutionService.execute(ExecutionService.java:126)
        at io.quarkus.smallrye.graphql.runtime.SmallRyeGraphQLSubscriptionHandler$TextMessageHandler.handle(SmallRyeGraphQLSubscriptionHandler.java:120)
        at io.quarkus.smallrye.graphql.runtime.SmallRyeGraphQLSubscriptionHandler$TextMessageHandler.handle(SmallRyeGraphQLSubscriptionHandler.java:109)
        at io.vertx.core.http.impl.WebSocketImplBase$FrameAggregator.handleTextFrame(WebSocketImplBase.java:621)
        at io.vertx.core.http.impl.WebSocketImplBase$FrameAggregator.handle(WebSocketImplBase.java:587)
        at io.vertx.core.http.impl.WebSocketImplBase$FrameAggregator.handle(WebSocketImplBase.java:576)
        at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
        at io.vertx.core.http.impl.WebSocketImplBase.receiveFrame(WebSocketImplBase.java:528)
        at io.vertx.core.streams.impl.InboundBuffer.handleEvent(InboundBuffer.java:240)
        at io.vertx.core.streams.impl.InboundBuffer.write(InboundBuffer.java:130)
        at io.vertx.core.http.impl.WebSocketImplBase.handleFrame(WebSocketImplBase.java:470)
        at io.vertx.core.impl.EventLoopContext.execute(EventLoopContext.java:71)
        at io.vertx.core.impl.DuplicatedContext.execute(DuplicatedContext.java:163)
        at io.vertx.core.http.impl.Http1xConnectionBase.handleWsFrame(Http1xConnectionBase.java:60)
        at io.vertx.core.http.impl.Http1xServerConnection.handleOther(Http1xServerConnection.java:163)
        at io.vertx.core.http.impl.Http1xServerConnection.handleMessage(Http1xServerConnection.java:149)
        at io.vertx.core.net.impl.ConnectionBase.read(ConnectionBase.java:155)
        at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:154)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
        at io.netty.handleByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:832)

2021-09-13 14:16:40,676 ERROR [io.qua.ver.cor.run.VertxCoreRecorder] (vert.x-eventloop-thread-7) Uncaught exception received by Vert.x: java.lang.NullPointerException
        at io.quarkus.smallrye.graphql.runtime.SmallRyeGraphQLSubscriptionHandler$SmallRyeGraphQLSubscriptionSubscriber.onNext(SmallRyeGraphQLSubscriptionHandler.java:171)
        at io.quarkus.smallrye.graphql.runtime.SmallRyeGraphQLSubscriptionHandler$TextMessageHandler.handle(SmallRyeGraphQLSubscriptionHandler.java:127)
        at io.quarkus.smallrye.graphql.runtime.SmallRyeGraphQLSubscriptionHandler$TextMessageHandler.handle(SmallRyeGraphQLSubscriptionHandler.java:109)
        at io.vertx.core.http.impl.WebSocketImplBase$FrameAggregator.handleTextFrame(WebSocketImplBase.java:621)
        at io.vertx.core.http.impl.WebSocketImplBase$FrameAggregator.handle(WebSocketImplBase.java:587)
        at io.vertx.core.http.impl.WebSocketImplBase$FrameAggregator.handle(WebSocketImplBase.java:576)
        at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
        at io.vertx.core.http.impl.WebSocketImplBase.receiveFrame(WebSocketImplBase.java:528)
        at io.vertx.core.streams.impl.InboundBuffer.handleEvent(InboundBuffer.java:240)
        at io.vertx.core.streams.impl.InboundBuffer.write(InboundBuffer.java:130)
        at io.vertx.core.http.impl.WebSocketImplBase.handleFrame(WebSocketImplBase.java:470)
        at io.vertx.core.impl.EventLoopContext.execute(EventLoopContext.java:71)
        at io.vertx.core.impl.DuplicatedContext.execute(DuplicatedContext.java:163)
        at io.vertx.core.http.impl.Http1xConnectionBase.handleWsFrame(Http1xConnectionBase.java:60)
        at io.vertx.core.http.impl.Http1xServerConnection.handleOther(Http1xServerConnection.java:163)
        at io.vertx.core.http.impl.Http1xServerConnection.handleMessage(Http1xServerConnection.java:149)
        at io.vertx.core.net.impl.ConnectionBase.read(ConnectionBase.java:155)
        at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:154)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:832)

Uploading image.png…

How to Reproduce?

Reproducer: https://github.com/SLedunois/authenticated-graphql

Steps to reproduce the behavior:

  1. Launch it with quarkus dev
  2. Go to http://localhost:8080/q/graphql-ui
  3. Log in with user graphql and password password
  4. Try to query query { get { id } } It works 👍
  5. Try to mutate mutation createUser{ create{ id } } It works 👍
  6. Try to use a subscription: subscription userCreated{ userCreated{ id } } It failes 👎

Output of uname -a or ver

Windows 10

Output of java -version

openjdk version "14.0.1" 2020-04-14 OpenJDK Runtime Environment (build 14.0.1+7) OpenJDK 64-Bit Server VM (build 14.0.1+7, mixed mode, sharing)

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.2.2.Final

Build tool (ie. output of mvnw --version or gradlew --version)

./mvnw clean package

Additional information

No response

@SLedunois SLedunois added the kind/bug Something isn't working label Sep 13, 2021
@quarkus-bot
Copy link

quarkus-bot bot commented Sep 13, 2021

/cc @jmartisk, @phillip-kruger

@phillip-kruger
Copy link
Member

/cc @sberyozkin

@sberyozkin
Copy link
Member

#16847 is probably related

@phillip-kruger
Copy link
Member

Sounds right yes, as we are using Websockets under the covers.

@SLedunois
Copy link
Author

Do we have a workaround ?

@sberyozkin
Copy link
Member

@SLedunois Where doe the credentials come from ? Do you mean you'd like to authenticate into Quarkus first say with the bearer JWT token and then have it associated with the GraphQL channel ?

@sberyozkin
Copy link
Member

@SLedunois Where do the credentials come from ? Do you mean you'd like to authenticate into Quarkus first say with the bearer JWT token and then have it associated with the GraphQL channel ?

@SLedunois
Copy link
Author

@sberyozkin It's just a Cookie authentication provided by build int authentication system.

@sberyozkin
Copy link
Member

sberyozkin commented Sep 13, 2021

@SLedunois I don't think the cookies are retained in a web socket channel.

The following suggests how it can be done:

https://coletiv.com/blog/using-websockets-with-cookie-based-authentication/

One can probably have a random value created at the server concatenated with the cookie obtained via the form auth. And bind to the web socket channel - and then when it comes in back to Quarkus via WebSockets - attach to RoutingContext from a GraphQL interceptor making Quarkus security think it is part of the standard HTTP request.

This is just a possible idea, may not be workable. I doubt Quarkus can help much in this particular case but I may be wrong...

@SLedunois
Copy link
Author

@sberyozkin Hum. A nice option could be to switch on Cookie authentication for loading my application and using a JWT to consume GraphQL API if GraphQL susbription authentication works fine with JWT ?

@ethan-gallant
Copy link
Contributor

The biggest problem I'm seeing with all the WebSocket implementations is their lack of an ability to handle contextual data.

Would it possibly be beneficial to add some form of abstracted extension capability to allow users to populate the security identity for websocket requests? And possibly refresh them?

My thinking is that users with a single Quarkus application running can just create an in-memory map similar to

Map<Token, SecurityIdentity> authTokens

Whenever a websocket request comes in, you're able to authenticate it and remove the entry from the map. Similar to a TenantResolver.

If someone has a clustered application, they would be able to swap the map out for a clustered key value like Redis with expirations.

What my takeaways are from websocket authentication are:

  • Sending JWTs in the Query is bad (see OIDC spec)
  • Some people send the bearer in the Query params anyways (@Netflix and their DGS app)
  • Many people use an in-memory map of tokens to identities which can be problematic for expired tokens and distributed apps.
  • There is no refresh functionality exposed for Security Identities which is publicly exposed in the Quarkus OIDC library.

@mswiderski
Copy link
Contributor

one comment about websocket is that the websocket session has way of storing some context data session.getUserProperties() that way it can be possible to associate the security context info there. I believe when token expires that should somehow trigger reconnect and by that onClose and then onOpen if websocket session which would lead again to setting the security context data.

@mswiderski
Copy link
Contributor

In addition, I'd like to also bring up option to be able to filter events push to the subscription based on the security context as described here smallrye/smallrye-graphql#1072

@ethan-gallant
Copy link
Contributor

Looking into the Apollo Spec, ConnectionParams is what should be used for WebSockets and GraphQL authentication.

ConnectionParams is an event that is sent over the Websocket from the consumer, it contains user-defined data to add metadata to the subscription such as credentials. Because this is done within the request there is no risk of leaking authentication credentials (bearers) in the query params.

Thinking of how this could plug into OIDC, would it be possible to handle ConnectionParams with an interceptor-style bean? The default implementation could accept something like Quarkus-Authorization: "Bearer ey----" or Quarkus-Code: oidc-code-flow-code and auto-authenticate the request context.

Are there any contextual problems that may come up when authenticating WebSockets in the traditional sense? (Request Context lifecycle) @phillip-kruger

@phillip-kruger
Copy link
Member

@jmartisk - f.y.i - if you are keen to look at this ^^^

@Bazalii
Copy link
Contributor

Bazalii commented Jan 24, 2023

Is there any progress on this issue?

@phillip-kruger
Copy link
Member

Nothing yet, are you keen to contribute ?

@Bazalii
Copy link
Contributor

Bazalii commented Jan 26, 2023

Nothing yet, are you keen to contribute ?

I will do my best to find time to solve this issue in the nearest future

@chemistfriend
Copy link

Is there anything new related with this? Tried to do some workaround but without success.

@ethan-gallant
Copy link
Contributor

@chemistfriend the best way I figured out to do this was with the raw Vert.x graphql API. We ditched Smallrye completely in favor of vertx. For our GraphQL API (non-websocket) we resorted to using Spring DGS (by Netflix) as it was a far better schema-first workflow.

If anyone on the Quarkus team is onboard to helping me get PRs merged between Quarkus and Smallrye GraphQL I am more than open to taking the time to implement the needed changes, but it's going to be an ongoing effort. Just give me a shout if this is something that is wanted on the Roadmap.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/graphql area/smallrye env/windows Impacts Windows machines kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants