Hello guys,
this is more of a question then issue.
Any recommendation on how to properly pass a JWT token when using subscriptions?
I was thinking of using connectionParams to pass the token, but as I understand this is passed during the initialization of the connection.
How to correctly handle SubscriptionClient / WebSocketLink when someone subscribes as non-authenticated user and after he loges in? Is it possible to call reconnect / re-subscribe?
Many thanks for help, and keep up the good work!
+1
connectionParams is the only documented way atm:
client: https://www.apollographql.com/docs/react/features/subscriptions.html#authentication
server: https://www.apollographql.com/docs/graphql-subscriptions/authentication.html
Once the user logs in, have you tried calling .close() and creating a new SubscriptionServer?
Don't know if INIT message can be sent later on in websocket's lifetime, but it would be nice to have a wsLink.sendNewConnectionParams() function on the client.
https://dev-blog.apollodata.com/new-release-of-graphql-subscriptions-for-javascript-f11be19e6569
Maybe something like this would work? The split would initially send things over unauthenticatedLink, and once the user logged in, would switch to authenticatedLink?
const unauthenticatedLink = new WebSocketLink({
uri: `ws://localhost:5000/`,
options: {
reconnect: true
}
})
let authenticatedLink = null;
onLogin(({ authToken }) => {
authenticatedLink = new WebSocketLink({
uri: `ws://localhost:5000/`,
options: {
reconnect: true,
connectionParams: {
authToken
}
}
})
})
const link = split(
() => !! authenticatedLink,
authenticatedLink,
unauthenticatedLink
)
Hello. I've tried to do that here https://github.com/apollographql/subscriptions-transport-ws/issues/171#issuecomment-352685470
It does work somehow but I get another problem. What do you think?
Chiming in here as well. In certain cases our access tokens can expire while a subscription session is active. As such, it would be nice to have a way to renew the authorization information on the subscription, without tearing down and re-establishing the subscription.
Yeah, for instance Auth0's web access tokens are default 2h, max 24h
@lorensr Would it make sense to add a first-class method to the client specifically for updating connection params?
Hey all, I was wondering if there's a way to actually close the subscription if I try to connect and the authentication fails on the server side. I've been playing around with the connectionCallback and getting the correct error from the server but I'm not able to actually close the connection or maybe stop it from reconnecting. Any ideas?
I just had this problem and solved it (partially) like this:
const wsLink = new WebSocketLink({
uri: `${process.env.REACT_APP_PUBLIC_URL
.replace('http', 'ws')
.replace('3000', '8080')}/subscription`,
options: {
reconnect: true,
connectionParams: () => {
return { token: localStorage.getItem('idToken') }
}
}
})
When connectionParams is a function, it gets evaluated before each connection. See the related code.
Yeah, I got that far. But dont know or don鈥檛 understand how to actually close the connection once connectionParams is invoked , this.close() does not work.
To force a reconnect without losing current subscriptions, you need to pass both arguments to close. Give client.close(false, false); a try.
So, this is my current code:
// WebSocket Link
const wsLink = new WebSocketLink({
uri: ws,
options: {
reconnect: true,
connectionParams: () => ({
authorization: `Bearer ${localStorage.getItem('mytoken')}`,
}),
connectionCallback: err => {
if (err) {
console.log('Error Connecting to Subscriptions Server', err);
}
},
},
});
I can detect the error but would like to stop the link from retrying and close the connection altogether if we have an error. In the context of the connectionCallback function I dont see any way to call client. Sorry if the question seems dumb, I'm not an expert :)
In this case you probably want to use the alternative version of WebSocketLink that allows you to pass in an instance of SubscriptionClient so that you can maintain a reference to it externally. You'd basically extract the internal constructor call into the code above. See https://github.com/apollographql/apollo-link/blob/master/packages/apollo-link-ws/src/webSocketLink.ts#L41 for how it uses the options you are already passing in.
Ok, I was able to get it to work! Thank you very much to all that chimed in. My code ended up as follows:
const wsClient = new SubscriptionClient(ws, {
reconnect: true,
connectionParams: () => ({
authorization: `Bearer ${localStorage.getItem('mytoken')}`,
}),
});
wsClient.connectionCallback = err => {
if (get(err, 'message') === 'Authentication Failure!') {
wsClient.close();
}
};
Just referencing #171
connectionParamsis the only documented way atm:client: https://www.apollographql.com/docs/react/features/subscriptions.html#authentication
Link is dead
I'm using Access & Refresh tokens JWT in server side. I can set new access token (after it's expiration time) as cookies in standard http. But i can't find how to send back new AccessToken to the socket client in OnConnect event for mobile apps. There is no documentation :(
Most helpful comment
Chiming in here as well. In certain cases our access tokens can expire while a subscription session is active. As such, it would be nice to have a way to renew the authorization information on the subscription, without tearing down and re-establishing the subscription.