[ ] Regression
[X] Bug report
[X] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
When I define a middleware like this:
import { Middleware, NestMiddleware, ExpressMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Middleware()
export class LoggerMiddleware implements NestMiddleware {
resolve(...args: any[]): ExpressMiddleware {
return (req: Request, res: Response, next: NextFunction): void => {
console.log('Middleware got executed!');
return next();
};
}
}
Then the console.log is never shown when I connect to my socket.io server from the client:
import * as socketIo from 'socket.io-client';
const manager: SocketIOClient.Manager = socketIo.Manager('/');
this.io = manager.socket('/asdf');
this.io.open();
this.io.emit('client_message', 'asdf');
All middlewares are also executed when sockets connect & get emitted
Not sure if it is intended like this or not. So I marked it as bug / feature
Nest version: X.Y.Z
For Tooling issues:
- Node version: XX
- Platform:
Others:
Hi @BorntraegerMarc,
What kind of middleware do you have in mind? Where do you apply them?
I had in mind to use the same logger / authentication middleware that I use for my "normal" HTTP requests. I'm aware of the interceptor concept for web sockets. I think it just feels weird to have interceptors for web sockets and middlewares for HTTP requests. Why are they not called the same?
@BorntraegerMarc I don't think that you can use the same middleware for authentication, there's no req, res on sockets. As far as I know, people suggests using jwt auth passing the token on each communication.
Depends on what kind of authentication you implement. If it's cookie based, then yes indeed: a normal middleware would not work because the req is not passed with each socket event. But with JWT usually you send the token manually from the FE
So for cookies I use a own adapter at the moment to get the req.cookie from new sockets
well, in FE maybe I would use an interceptor to automatize jwt sending and in BE a guard should do the trick. Checking documentation, I can't see any type of middleware on gateway section, and neither checking on GatewayMetadata code.
I've also tried with interceptor logging & websockets and it works.
No documentation exists for Middlewares in sockets because I don't think it's officially supported. Not sure though :)
Interceptor is definitely working. But I think it's a bit confusing to use an interceptor when actually a Middleware is wanted...
Well, finally I've done logging with interceptors and auth with guards together with socket.io and it seems to works ok. For auth in nest, it's suggested guards more than middlewares. Maybe the best approach would be rewrite your http auth on guards...
For sockets, you can use passport jwt and implement jwtFromRequest on jwt-strategy.
Guards do not have access to the HTTP request when a websocket connection is being established. So can't use them to get the HTTPOnly Cookie where my session is stored...
Yes, that's true, but I doubt if there's another better way to achieve token handling with ws. If it would exists any kind of middleware on ws probably wouldn't have access to request because only matters data interchanged when communication is stablished.
@kamilmysliwiec what do you think?
In Nest v5.0.0 you'll have an access to each argument, meaning, you could use a client
instance to pick up the token
In Nest < 5 you have to put this logic directly into gateways
@kamilmysliwiec yes, that's what I'm doing now at the moment. But I wonder if the functionality for v5.0.0 should be changed to match more with the normal HTTP functionality
But even in Nest >= 5, for being able to get the token on BE, you need to pass it on every emit payload from FE or it exists any better way in websockets that allows you to access the token in BE if it's being used httpOnly cookies?
In my opinion the token / cookie should only be passed when the connection between client & server is being established.
So currently I just use a socket.io middleware with an custom implemented adapter that checks the value of the token / cookie.
If the token / cookie is not valid I call socket.disconnect();
-> So I know that I never have unauthenticated sockets to take care of.
You have the opportunity to use nest middleware for that purpose as the following example
@Middleware()
export class AuthenticationGatewayMiddleware implements GatewayMiddleware {
constructor(private readonly userService: UserService) { }
resolve() {
return (socket, next) => {
if (!socket.handshake.query.auth_token) {
throw new WsException('Missing token.');
}
return jwt.verify(socket.handshake.query.auth_token, 'secret', async (err, payload) => {
if (err) throw new WsException(err);
const user = await this.userService.findOne({ where: { email: payload.email }});
socket.handshake.user = user;
return next();
});
}
}
}
And then you can apply it in the gateway
@WebSocketGateway({
middlewares: [AuthenticationGatewayMiddleware]
})
I hope that can help you if you are using nest under v5
@adrien2p thanks! I'll tests that out
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
You have the opportunity to use nest middleware for that purpose as the following example
And then you can apply it in the gateway
I hope that can help you if you are using nest under v5