Apollo-link: Cannot identify subscription users once the WebSocketLink has been configured.

Created on 17 May 2018  ·  3Comments  ·  Source: apollographql/apollo-link

I'm having trouble identifying users who have connected with web sockets. Here is how you can reproduce this issue:

1) Create a new client and configure a WebSocketLink with connectionParams.

    const wsLink = new WebSocketLink({ 
      uri: `ws://localhost:3333`, 
      options: { 
        connectionParams: {
          lazy: true,
          authToken: localStorage.getItem('token')
        }
      } 
    });

At this point the user has not logged in, there is no token. The websocket also has not yet connected, because lazy is set to true. It doesn't connect until until the first subscription has been sent, after the user has logged in.

When the user does log in, and the connection has been made, the authToken is null because this value was set when the client was configured, not after the user has logged in.

    subscriptionServer.onConnect = params => {
      console.log('connected: ', params.authToken) // null
    }

Queries and Mutations are authorized by concatenating links:

const httpLink = new HttpLink({ uri: GRAPHQL_ENDPOINT })
const authLink = new ApolloLink((operation, forward) => {
    const token = localStorage.getItem('token')
    if (token) {
        operation.setContext({
            headers: {
                authorization: `bearer ${token}`
            }
        })
    }
    return forward(operation)
})

const httpAuthLink = authLink.concat(httpLink)

I can identify users this way because the token is added to the authorization header when the request has been sent after the user has logged in. The problem with the WebSocketLink connection params is that it reads the token when the client is being configured before the user has logged in.

Most helpful comment

dont do that, try this:

connectionParams: () => ({
          lazy: true,
          authToken: localStorage.getItem('token')
        })

All 3 comments

I've been able to find a temporary solution. After the user is identified and their token is saved to the browser, I refresh the page: window.location = '/'. If feels so dirty though.

Any thoughts on adding onConnecting and onDisconnect methods to the constructor options of the WebSocketLink? This approach will prevent any need to refresh the page.

const wsLink = new WebSocketLink({ 
      uri: `ws://localhost:3333`, 
      options: { 
        onConnecting: () => {
                // Invoked just before the Socket initially connects
                // returns additional connection params
                return  {
                   authToken: localStorage.getItem('token')
               }
        },
        onDisconnect: () => {
                // Invoked when the socket is disconnected
       }
      } 
    });

dont do that, try this:

connectionParams: () => ({
          lazy: true,
          authToken: localStorage.getItem('token')
        })

Thank you @gpbaculio

Was this page helpful?
0 / 5 - 0 ratings