I'm building an app that use SignalR to transmit realtime message and I was wandering if there was any way for me to disconnect user on the server side.
I want to disconnect them because of the way SignalR handle authentification. Signalr dosen't seem to check if a token is expire inside an open websocket connection (it only check at the start of the request or when the client send a message).
Another solution would be to disconnect the client after a given time.
For the moment all I have for the authentification is a JWT token sent inside the accessTokenProvider.
ClientSide :
new HubConnectionBuilder()
.withUrl(`${env.APPURL}/hub`, {
skipNegotiation: true,
transport: HttpTransportType.WebSockets,
accessTokenFactory: async () => {
const { token } = store;
return token;
},
})
I handle this on the client side. My angular application uses a silent refresh token call to refresh the jwt token and keep the user authenticated.
When I added SignalR functionality to my app, I also needed to update the access token for the active SignalR connections. After some research, the only way to do this is to 'reset' the connection. When you stop and start the connection again, SignalR will use the newest token you pass to it via the access token factory.
If you wanted to do this server side, you could send a message to all the clients, upon which the clients stop their connection and immediately restart it.
Ultimately, the code that stops the connection has to be done on the client side.
-- UPDATE --
ASP.NET Core SignalR has the Abort method in the Hub class. (It is not possible to do this in ASP.NET SignalR however.)
With this Abort method, you could run your logic on a per connection basis and if the connection needs to be stopped then:
public void AuthenticateConnection()
{
// Run your logic to determine if connection needs to be stopped
// If connection must be stopped
Context.Abort();
}
Although this does stop the connection, it provides no way to start it again, and as such you're stuck with the client permanently disconnected. So if you intention is to update the clients bearer token, then I am not sure this would work for you.
For the use case of updating the JWT bearer token, I would recommend setting a 'refresh-token' timer on client side as you get the token.
E.G. If I log in and the token expires 15 minutes from now, I will set a 14 minutes timer, after which I will refresh the token to keep the user logged in. Every time the token is successfully refreshed, I then stop and start the connection (passing the updated token).
If it is imperative that you do this from server side, one solution could be to send a disconnect message out along with a client id, then the client with that id will receive the message:
server side
Clients.All.SendAsync($"disconnect-{clientId}");
client side
this.connection.on(
`disconnect-${this.clientId}`, async () => {
await this.connection.stop();
await this.connectionstart();
}
);