NestJs socket authentication, emit event in handleConnection - socket.io

Upon failed authentication, before disconnecting, I want to emit an event to the client informing that the token provided with the request is invalid. In my WebSocketGateway this is my code:
handleConnection(client: Socket, ...args: any[]) {
try {
this.socketAuthService.authenticate(client);
this.logger.log(`Client connected: ${client.id}`);
} catch (e) {
this.logger.error(`Client ${client.id} tried to connect with invalid token`);
client.emit('unauthorized', 'Invalid Token');
client.disconnect();
this.logger.log(`Client disconnected due to invalid token: ${client.id}`);
}
}
My client:
this.socket.on('unauthorized', (msg) => {
console.log(msg);
});
The event is not sent / received. Any idea?
Cheers

What you need is to close the socket with a custom socket error code and a message. You can do this by using socket.close(code, message);
socket.close(4004, "Unauthorized Request");
You will get an exception like this
Postman exception on websockets invalid origin

Related

Why does "instanceof" return true on the server side but return false on the client side?

I am using Yup to validate register inputs on the server side using a Next.js API route.
Although the validate function returns an error on the server side which is an instance of ValidationError, when sending the same error to the client side and checking again if it is an instance of ValidationError the same error returns false.
Server side code:
try {
const validation = await registerYupSchema.validate(registerData)
} catch (error) {
if (error instanceof ValidationError) {
return res.status(400).send({ error })
}
return res.status(500).send({ error: 'Validation failed' })
}
Client side code:
const response: Response = await fetch(endpoint, options)
const { error } = await response.json()
if (error && error instanceof ValidationError) {
} else if (error) {
setError(error)
}
I checked with console.logs where and what exactly is sent back to the client. The status code was 400 and the console.log within the if-statement on the server side was triggered successfully. Still, on the client side the if-statement returned false and the else-if-statement ran instead of it.

Coinbase-pro for Node.js - Websocket connection breaking with error: read ECONNRESET

I'm currently stuck with an issue I'm getting with the coinbase-pro-node npm package (https://github.com/coinbase/coinbase-pro-node). I'm connecting to the matches channel and listening for messages there but the connection with the Websocket breaks after a few hours without telling me much. I can't trace back the problem and it doesn't happen on the same intervals. Sometimes it breaks just minutes after I run the script. Thanks for the help.
The code:
const CoinbasePro = require('coinbase-pro');
var coinbaseWs = '';
function connect() {
coinbaseWs = new CoinbasePro.WebsocketClient(
['BTC-USD'],
'wss://ws-feed.pro.coinbase.com',
{
key: 'xxxx',
secret: 'xxxx',
passphrase: 'xxxx',
},
{ channels: ['matches'] }
);
coinbaseWs.on('message', async data => {
console.log(data)
});
coinbaseWs.on('error', err => {
console.error("Connection with Coinbase websocket failed with error: " + err);
console.log("Error stack trace: " + err.stack);
});
coinbaseWs.on('close', () => {
console.error("Connection with Coinbase websocket closed!");
});
}
connect();
Error stack:
Error: read ECONNRESET
File "internal/stream_base_commons.js", line 167, in TLSWrap.onStreamRead
it does break from time to time for no apparent reason. All you can do is listen for the heartbeat messages and use those to decide whether to re-initiate a new websocket feed. I raised a similar query directly with the coinbase pro/gdax customer support.

Where do I handle feathersjs/socketio-client connection error

I'm using feathers with socketio in backend. The client is listening and everything works well.
I want to handle the 'server not responding' error and I don't find where can I do that?
The error thrown by the server:
"Unhandled promise rejection
Object { type: "FeathersError", name: "Timeout", message: "Timeout of 5000ms exceeded calling find on newsfeed", code: 408, className: "timeout", data: {…}, errors: {}, stack: "FeathersError#webpack-internal:///./node_modules/#feathersjs/errors/lib/index.js:58:19\nTimeout#webpack-internal:///./node_modules/#feathersjs/errors/lib/index.js:135:3\nsend/</timeoutId<#webpack-internal:///./node_modules/#feathersjs/transport-commons/lib/client.js:66:9\n" }"
It is correct, the 'promise' is not handled! Where do I handle?
I tried adding catch on each line just to see what works but without success:
import feathers from '#feathersjs/feathers'
import socketio from '#feathersjs/socketio-client'
import io from 'socket.io-client'
const socket = io('http://localhost:3030/', {transports: ['websocket']});
socket.on("connect_failed", er=>console.error('Error connecting to server: ', er));
const restApi = feathers()
.configure(socketio(socket));
try {
restApi.service('/newsfeed');
restApi.on("connect_failed", er=>console.error('Error connecting to server: ', er));
}
catch (er) {
console.error('Error connecting to server: ', er)
}
export default restApi
The timeout error is coming from a particular request so you have to handle it wherever you are making the request.
restApi.service('/newsfeed').find()
If you're using async/await, you can wrap your service call in a try/catch or my personal favorite is just putting a catch on the call;
// try/catch
try {
const response= await restApi.service('/newsfeed').find();
catch(e) {
// handle e
}
//just use catch
const response= await restApi.service('/newsfeed').find().catch(e => {
// handle e
});
If you're using promises, just use a catch:
restApi.service('/newsfeed').find().then(response => {
// handle response
}).catch(e => {
// handle e
});

Observer.error is not sending the error

I am trying to generate an intermediate service between a request service and the angular component that subscribes to it. To achieve that, I generate an observable from httpClient request that connects with the intermediate service, and sends the HTTP response.
When the response arrives to the intermediate service, I generate another observable that connects with the client component.
The problem starts here. As I get a 500 status response from request, I get that response in the intermediate service, but when I try to send to the client component with a subscribe.error(err) it starts a loop that never ends, getting the following error:
You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
I am using the same observer.error(err) in the request service and in the intermediate service, and it works correctly only in the request.
Request:
Observable.create((observer: Observer<any>) =>
this.httpClient
.request(httpRequest)
.subscribe(
...
(res: HttpErrorResponse) => {
observer.error(res);
observer.complete();
},
() => {
observer.complete();
},
}
Intermediate Service:
Observable.create((observer: Observer<any>) =>
this.requestService.request(requestServiceOptions).subscribe(
...
(err: HttpErrorResponse) => {
if (err.status === 401) {
this.callbackWhenRequestFails();
} else {
observer.error(err);
observer.complete();
}
}
It has been solutionated.
Unfortunately, when catching the error I was using return instead of throw, then that's why the console was showing the stream error!

How to handle authentication errors in socket.io with socketio-jwt

Following the example for https://github.com/auth0/socketio-jwt , I couldn't get the authentication failure to fire.
How are you supposed to handle and configure authentication errors using this library? I see in the source code that it is supposed to throw an UnauthorizedError but I just can't seem to trigger it.
Server side
io
.on('connection', socketioJwt.authorize({
secret: 'test',
timeout: 7000
}))
.on('authenticated', (socket) => {
console.log('connected user: ' + socket.decoded_token.name);
});
Client side
socket.on('connect', function () {
socket.emit('authenticate', {token: 'badtoken'}); //send the jwt
});
socket.on("error", function(error) {
// this never fires
if (error.type == "UnauthorizedError" || error.code == "invalid_token") {
alert("User's token has expired");
}
});
Do I need to add an .on('error, function(error)) on the server code as well?
Looking at the source code for jwt, they are actually emitting "unauthorized", not "error". Change to
socket.on("unauthorized", function(error) {
// this should now fire
if (error.data.type == "UnauthorizedError" || error.data.code == "invalid_token") {
alert("User's token has expired");
}
});
This bug in the doc and examples was also reported here.

Resources