Graphql-flutter: WebSocketLink doesn't add headers from AuthLink

Created on 10 Sep 2019  路  15Comments  路  Source: zino-app/graphql-flutter

This scenario works in apollo-graphql, just by setting the right Authorization token on the WebSocketLink;

Here, for some reason, the Authorization header is not being sent to the server even when the AuthLink is present and is injecting the right headers.

This problem might be related to the underlying websockets client or the fact that websockets work by sending an initial connection request to the server.

I think we should add something similar to what AuthLink does with getToken() on WebSocketLink, like: getInitialConnectionHeaders(), so those headers are sent to the server when connection_init happens.

Error message:

E/flutter (17683): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: {type: error, id: 2d90df21-b556-4291-98ad-f36cdc538b39, payload: {extensions: {path: $, code: start-failed}, message: cannot start as connection_init failed with : Missing Authorization header in JWT authentication mode}}

More insight about this issue:
https://github.com/hasura/graphql-engine/issues/994

Most helpful comment

It looks like setting headers for the SocketClientConfig was allowed earlier. However, it has been removed because "WebSocket headers are not usable in the browser". The suggestion is to use initPayload. I have tried these settings below and it worked out on 2.1.0!

      config: SocketClientConfig(
          autoReconnect: true,
          inactivityTimeout: Duration(seconds: 30),
          initPayload: {
            "headers": {"Authorization": 'Bearer ' + token}
          }),

I think setting up SocketClient with headers for Authorization to use with Subscriptions should be documented for clarification.

All 15 comments

This link from apollo has more info
https://github.com/apollographql/graphql-subscriptions/blob/master/.designs/authorization.md

It鈥檚 not possible to provide custom headers when creating WebSocket connection in browser.

I too need to figure out how to do it, hope you can figure out a wasy. Cheers

This happened to me on Hasura, I'll contact them and get back to this issue with more information.

I haven't worked with Hasura and Web Socket that much, but last week I came across a series of blogs post on Hasura and Flutter, for this library. Here are the links, you can skip the first two blog posts.

  1. https://blog.hasura.io/build-flutter-app-graphql-hasura-serverless-part1/
  2. https://blog.hasura.io/build-flutter-app-hasura-firebase-part2/
  3. https://blog.hasura.io/build-flutter-app-hasura-firebase-part3/

I will work to create a meaningful example soon on using Hasura and Flutter, I hope that helps in the meantime.

@mainawycliffe Thanks for the reference! In fact, I talked to Can Ta艧p谋nar (The author of that blogging series, who was very kind and helpful). This seemed to be working on v1 (^1.0.0), but latest versions throw that error. I'll look at the source code differences to know if we can get this to work. At the moment a workaround is to set the dep version to ^1.0.0

Attachment:
How my client and links look

Screen Shot 2019-09-11 at 00 02 37

It looks like setting headers for the SocketClientConfig was allowed earlier. However, it has been removed because "WebSocket headers are not usable in the browser". The suggestion is to use initPayload. I have tried these settings below and it worked out on 2.1.0!

      config: SocketClientConfig(
          autoReconnect: true,
          inactivityTimeout: Duration(seconds: 30),
          initPayload: {
            "headers": {"Authorization": 'Bearer ' + token}
          }),

I think setting up SocketClient with headers for Authorization to use with Subscriptions should be documented for clarification.

@cantaspinar Yes, that was changed when flutter for web was announced. The docs are kind of a mess at the moment. I will dedicate some time to updating the docs and possibly a static site for the library of the coming weeks.

@cantaspinar how would one refresh their token when it expires?

@kulture-rob Hmm, I assume you are talking about Firebase tokens which expire after an hour. I have to find a way to deal with that too but haven't tried anything yet. I guess there is no way to mutate the links after they have been passed to GraphQLProvider. Maybe you can catch errors when making requests to GraphQL api and if the token is expired, reload the token and rebuild. Provider package might be handy to achieve that.

@cantaspinar how would one refresh their token when it expires?

What I do:

  • I still use AuthLink for regular HTTP requests, and use firebase's getIdToken() function to refresh the token and send it over the HTTP request.
  • For WS Connections this works a little bit different, because the token is sent only on the initial web socket handshake. It is only sent once the connection is made. So you must get an updated token with getIdToken() before creating the client. Then you don't need to worry about expiration because your connection via WS has already been authenticated.

This is how my client looks at this point:

codea

for me initPayload don't work, don't send my custom header. any alternative to send headers on SocketClientConfig?

This should definitely be documented!

Once #546 gets merged in, you can do it like getToken()

Can we reopen this? Adding headers to initPayload doesn't add them to the request

    final WebSocketLink websocketLink = WebSocketLink(
      url: ApplicationConstants.graphqlSubscriptionURI,
      config: SocketClientConfig(
          autoReconnect: true,
          inactivityTimeout: Duration(seconds: 15),
          initPayload: {
            "headers": {"Authorization": 'Bearer ' + "FAKE TOKEN"}
          }),
    );

Headers from Charles

聽 | GET /graphql HTTP/1.1
-- | --
user-agent | Dart/2.8 (dart:io)
connection | Upgrade
cache-control | no-cache
accept-encoding | gzip
content-length | 0
sec-websocket-version | 13
host | localhost:20002
sec-websocket-extensions | permessage-deflate; client_max_window_bits
sec-websocket-key | [REDACTED]
sec-websocket-protocol | graphql-ws
upgrade | websocket


@KieranLafferty it has been merged into beta, but hasn't been released.

Was this page helpful?
0 / 5 - 0 ratings