Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Allow web-ui users to configure the payload on connection_init messages when subscribing over websockets #2181

Closed
soenkehahn opened this issue Feb 18, 2022 · 7 comments · Fixed by #2719

Comments

@soenkehahn
Copy link

We are implementing a graphql server where clients can subscribe (using graphql subscriptions) and have to authenticate by sending an auth token in the payload of the initial connection_init message. So -- for example -- an initial message could look like this:

{
  "type": "connection_init",
  "payload": {
    "Authorization": "Bearer <some-jwt>"
  }
}

Is there a way in the graphiql web frontend to configure the payload that is being sent in the connection_init message? We couldn't find a way and graphiql is broken for us.

For context: We're using https://github.com/99designs/gqlgen for implementing the backend. gqlgen switched to using graphiql here: 99designs/gqlgen#1751. Before that it used https://github.com/graphql/graphql-playground. As far as I can tell, that project behaved like this: If users entered headers in the web frontend, it would:

  • Put those headers into the http request headers for queries and mutations. These requests would not use websockets.
  • For subscriptions, it would open a websocket, for the initial http update request, it would not include the custom headers, but then it would put the custom headers into the payload of the connection_init request.
@acao
Copy link
Member

acao commented Feb 19, 2022

Huh! I wasn’t aware that the graphql-ws protocol spec allowed customizing this. @enisdenjo is there a configuration setting for this in graphql-ws or is this initialization message a fixed part of the protocol?

@acao
Copy link
Member

acao commented Feb 19, 2022

As long as gqlgen follows the official protocol spec that the community is consolidating around this should work, so it may just be a matter of passing a custom option to graphql-ws which is exposed in the createGraphiQLFetcher() client creation method

i know gqlgen isn’t too worried about following the official protocol specs when it comes to innovating (RPC 😍) and that’s what I like about it!

but GraphiQL is a reference implementation so we have to follow the RFCs of course. If you need to, you can create a custom utility to generate your Fetcher that adheres to a modified version of the spec, or you could use patch-package to patch graphql-ws to your liking

@enisdenjo
Copy link
Member

Huh! I wasn’t aware that the graphql-ws protocol spec allowed customizing this. @enisdenjo is there a configuration setting for this in graphql-ws or is this initialization message a fixed part of the protocol?

Of course. The ConnectionInit message can hold an optional payload for any metadata the implementor sees fit.

The graphql-ws client takes a connectionParams argument to fill this connection init payload.

@soenkehahn
Copy link
Author

@acao: Thanks for the replies. As I understand it, the spec does specify an optional payload field. And graphql-ws also supports that. I did some digging and graphiql also already allows to specify the payload in javascript, for example like this:

GraphiQL.createFetcher({
  url,
  subscriptionUrl,
  wsConnectionParams: { Authorization: 'Bearer <token>' }
});

wsConnectionParams is declared here and passed through to graphql-ws as the connectionParams argument that @enisdenjo mentioned.

This issue is about allowing users of the graphiql web interface to configure the payload without having to write javascript. (I'll change the title of this issue to make it a bit more explicit.)

As I mentioned above https://github.com/graphql/graphql-playground just passes whatever users put into the 'headers' as a json object into that payload. Which I find a bit weird, since it kind of conflates http headers and this payload field. But that would work for us. Any other way to configure the payload would also work, though.

If I find the time, would you be willing to review a PR that added this? Pending a decision on how this should be supported in graphiql.

@soenkehahn soenkehahn changed the title Allow to configure the payload on connection_init messages when subscribing over websockets Allow web-ui users to configure the payload on connection_init messages when subscribing over websockets Feb 19, 2022
@acao
Copy link
Member

acao commented Feb 19, 2022

@soenkehahn ah ok, I understand much better now!

yes we have a very different approach to the API for playground. the user configuration is much more high level, static configuration. with GraphiQL, the customization happens through component props and is generally more programattic. Generally, users add additional UI of their own for additional user controls and settings. This is about to get better in 2.0 with custom panes.

So, this may solve part of your problem - I'm noticing that we never bothered to pass the configured headers to wss connection params when we made the contrib fetcher last year! Already with HTTP GET/POST we pass a combination of the configured default headers and the user-provided headers. We shouldn't assume that the same headers are used between HTTP/S and WS/S, but I've never seen an implementation where different authorization headers were used. And what's more, your issue helped me notice we haven't done the same for HTTP multipart IncrementalDelivery either.

The resultant fetcher function has two additional parameters we can use, and we aren't using any! yikes!

this utility is brand new, essentially a simplistic reference client for IDE usage. Before, we just told people to generate their own fetcher. so there is a ton of room for improvement here in this very young utility!

@andreialecu
Copy link
Contributor

I also ran into this while switching to Mercurius from Apollo. Mercurius uses graphiql, while Apollo used the graphql playground.

All our subscriptions need authentication, passed via the connection_init payload. The graphql playground used to pass the Headers as the payload, but graphiql does not.

This makes working with subscriptions currently impossible unless I'm missing something.

@acao
Copy link
Member

acao commented Aug 28, 2022

@acao acao closed this as completed Aug 28, 2022
@graphql graphql locked and limited conversation to collaborators Aug 28, 2022
@acao acao converted this issue into discussion #2717 Aug 28, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants