I have a socket/channel setup with some custom authentication logic. If the authentication fails, it shows an error message to the user (so they can fix the problem). Right now this is handled at the channel level–basically all socket connections are accepted, but only properly authenticated sockets can join particular channels.
I’d prefer to move auth checking to the socket level, so unauthenticated connections get refused with a 403 (that would prevent accidental and/or malicious unauthed connections from holding unnecessary socket connections). The problem I’m running into: socket authentication failures seem to be handled the same way as “normal” connection failures by the client (triggering onClose and onError with generic close events, starting retries, etc.).
So my question: is there any way to have custom handling for socket authentication errors on the client side? I’d like “normal” connection failures to use the default behavior (retries, etc.) but authentication failures to not retry and instead alert the user. Thanks in advance!
I was unwilling to accept that this is impossible, so I’ve come up with the following hack that works to resolve the issue of a Phoenix Socket that has an expired authentication token, causing it to return a 403 when the client tries to reconnect. This happens, for example, when the user has left a page open for hours on end, so the token is expired, but the Phoenix Channel client is still trying to reconnect and the page itself is still loaded in the browser, so it has no idea that its token is expired.
I’m battling with the same problem. My solution is to not have authentication on the socket connection, but move it to the channels. Specifically to the “general” channel. If there is no authentication information, the channel will send an “unauthorized” response, which will trigger the login process again.
Since JWT tokens can be inspected / the data pulled out, I’m going to check my refresh token’s exp claim to determine if it’s expired. (Probably with a clock drift tolerance; meaning if it expires in the next ~30 seconds I count it as expired.)
Then I’ll add an onError or onClose handler that:
Checks if our current token is expired.
If so, refreshes and then re-creates the Socket object with the new credentials in the params.
If not, just no-ops.
Slightly inefficient / hacky feeling, but it should work. I’ll report back with the results.
JWT tokens are generally supposed to have a very short life, like 30 seconds to a minute max is usual, anything longer is almost certainly a misdesign as it makes it easier to reuse, so be careful with it.