#How to extract a jwt from a request, but with websockets?
1 messages · Page 1 of 1 (latest)
the schema is also fairly simple as well
I'm not sure if I need to create new namespaces/not sure what namespaces really do besides give the actual socket a name
We do check JWT token on handshake request with custom auth service.
do you need something like this
https://github.com/recepkefelii/uno-online/blob/Dev-V0.2/server/src/socket/socket.gateway.ts#L20
Uno Online is a real-time multiplayer game built with cutting-edge technologies such as Nest.js, React, Socket.io, and Redux. Play Uno with friends and experience fast-paced and engaging gameplay o...
in this code when connecting to socket i get the token with header and validate the token
i check if the user information is limited i connect the user to the room with socket.io
or you can write a guard for ws and add the client user object and get the decorator and user information.
// guard
import { ExecutionContext } from "@nestjs/common";
import { AuthGuard } from "./auth.guard";
export class WsAuthGuard extends AuthGuard {
canActivate(context: ExecutionContext): boolean {
const client = context.switchToWs().getClient();
const headers = client.handshake.headers;
if (!headers.authorization) {
return false;
}
const user = this.validateToken(headers.authorization);
client['user'] = user;
return true;
}
}```
```ts
// Decorator
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
const UserDecorator = createParamDecorator((data: undefined, ctx:ExecutionContext) => {
const user = ctx.switchToWs().getClient()
return data ? user.user[data] : user.user;
})
export default UserDecorator```
```ts
// use
@SubscribeMessage('start')
@UseGuards(WsAuthGuard)
async start(@ConnectedSocket() socket: GameSocket, @UserDecorator() user: IGetUserType) {
const result = await this.rulesService.start(user,socket.gameId)
socket.to(socket.gameId.toString()).emit('game_start',result)
}```
oh okay I’ll definitely check this out
thank you so much!!
have you tested this with a UI and postman?
okay sorry for the follow up question, but how where does this statement return the message to? socket.gameId or game_start?
i'm fairly new to understanding sockets and this is the only way I can get a response from the initial socket request is to use the
@WebSocketServer()
server: Server
using
@ConnectedSocket()
socket: Socket
never returns the emitted message from the server
this was the only way I was able to return a message from a listening websocket
you can create socket.io rooms
In this code the example sends a message to those listening game_start among all clients entering the same room
so that would be when I do something like
@SubscribeMessage('joinRoom')
async joinRoom(
@ConnectedSocket()
socket: Socket,
@MessageBody()
data: any
) {
socket.join('room');
}
if this is correct how would I access that room from another function?
i don't create rooms with socket and joinrooms
how would you create a room then?
cause I thought by default the connected socket creates a room with it's respective ID?
or is that room the one you are referring to?
sorry if if I sound a little dumb on the subject I'm very new to learning websockets
When the client connects via socket i check which room they are in by using the token in the header and then add it to the socket object.
example user creates a room with HTTP requests and another user joins the room I add these users to the database
When the client connects with a socket I retrieve the room where the user is located by taking the token from the header and add it to the Socket object this way, I can access the gameId from my events.
actually, you can join rooms with sockets but I dont think it makes much sense to create rooms
okay that makes a lot more sense
if we were to take this example how would I add a the chatRoomId to the socket?
as far as I know this just spits out the Id back to the original socket
I would first have to add @ConnectedSocket() socket: Socket to my params correct?
yes correct @ConnectedSocket() socket: Socket
what would my next step be cause you stated previously that you didn't have to use socket.join('room') how else would you add the roomId to the socket Object?
I noticed that you created an extended class of the Socket object and had a gameId is that what you're referring to?
and I would do something similar and create a ChatSocket? and extend the class and add a chatId to that?
i use this here
.
yep
export GameSocket extend Socket {
gameId: number
}
It's actually easy in essence, but there are many factors.
looking at your code I'm assuming that once you call the joinGame endpoint on your game controller once that response is good you actually connect them to the socket?
if I'm understanding that is correct?
it seems like you have found a bug, thank you
The current implementation works in a way that if a successful response is received from the request it enters the room but it is not mandatory to establish a socket connection However if the game has already started the socket cannot be connected
I forgot to check whether the game has started or not here
omg hahaa that's so funny
but yea my idea of a successful response is whether or not they are connected to that game
what you said is actually true
is there some different logic that I'm missing that would cause this to not run properly or properly emit a message? because when I have previously tried this it doesn't want to emit a message through the @ConnectedSocket() socket: Socket but if I use @WebSocketServer() server: Server it actually emits the message
where would I find this connectedSocket on postman or is it something that I can't use postman for and need an actual UI to test?
import { Socket } from "socket.io";
check it's right
yes that is correct
I've actually made sure that was the correct import when testing it
make sure you download the correct packages
https://docs.nestjs.com/websockets/gateways
Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reactive Programming).
yep I have them
I can only receive the socket when using this.server.emit('test', 'this returns something')
if I tried using the socket it wouldn't return a message or anything
can you share all the code page
Can you put handleDisconnect etc implementations in a different file?
yea
import { Logger, UseGuards } from '@nestjs/common';
import { ConnectedSocket,
MessageBody,
SubscribeMessage,
WebSocketGateway,
WebSocketServer
} from '@nestjs/websockets';
import { Socket, Server } from 'socket.io';
import { ChatService } from './chat.service';
import { AuthService, PrismaService, } from 'src/modules';
import { CreateChatDto, CreateChatRoomDto } from 'src/utils/types';
import { JwtPayload } from 'src/utils/types/jwt';
import { WsGuard } from '../auth/guards';
import { GetWsUserId } from 'src/decorators';
@WebSocketGateway(80, {
cors: {
origin: process.env.CORS_ORIGIN,
}
})
export class ChatGateway {
private logger: Logger = new Logger(ChatGateway.name);
constructor(
private readonly authService: AuthService,
private readonly chatService: ChatService,
private readonly prisma: PrismaService,
) { }
@WebSocketServer()
server: Server
@SubscribeMessage('message')
async sendMessage(
@ConnectedSocket()
socket: Socket,
@MessageBody()
message: CreateChatDto
) {
return await this.chatService.sendMessage(this.server, message);
}
@SubscribeMessage('createChatRoom')
async createChatRoom(
@ConnectedSocket()
socket: Socket,
@MessageBody()
data: CreateChatRoomDto,
) {
const { id }: JwtPayload = await this.authService.parseJwt(data.jwt);
const users = [id, data.userId];
const chatRoom = await this.prisma.chatRoom.create({
data: {
users: {
connect: users.map(id => ({ id: id }))
}
}
});
socket.join(chatRoom.id);
this.server.emit('createChatRoom', chatRoom.id);
}
}
well when I use this.server.emit('createChatRoom', chatRoom.id)
it works
when I use socket.emit('createChatRoom', chatRoom.id) it doesn't work
another example would be this.server.to(chatRoom.id).emit('message', data) where would I have to be listening to grab this message?
in your example right here
I am listening to the events
but it would only listen to that response once I used this.server.emit('createChatRoom', chatRoom.id)
same
no difference
so it didn't work for you either? or no difference to what? it's the same thing?
I would listen to the message event?
currently when I do
this.server.to('test').emit('message', data)
it doesn't work
works
this.server.emit('message', data)
not entirely sure what the difference is
the code this.server.to('test').emit('message', data) sends the data to all clients that are listening to the message event in the test room
first join room
socket.join("test")
send only to those in this room
socket.to("test").emit("message",message)
is there a way I can join a room in postman to see this happening?
or can that only be done from an actual client?
dont need
you need
log(socket.room)
if we take this example test example
how would I receive this emitted message on hello?
I am seeing that I am joining the socket but now I'm not receiving the message
You should listen to postman hello event from a different tab
it did not receive the message
because wouldn't I also have to join the test room?
for this to work?
yep
because like you said it would only be received by those that are also listening/joined that specific room?
Exactly
so I woulnd't be able to test it on postman
I would need to actually connect to the server from some sort of UI to see this actually working in practice
if I'm understanding correctly
nope
@SubscribeMessage('send1')
async test(@MessageBody() body:,@ConnectedSocket() sokcet:GameSocket){
sokcet.join("1")
}
@SubscribeMessage('send2')
async test123(@MessageBody() body:,@ConnectedSocket() sokcet:GameSocket){
sokcet.to("1").emit("test",2 | body)
}
try this
open 2 Postman tabs and connect
in the first tab and second tab send a message to the address send1 the content of the message doesnt matter.
then in the first tab listen for a test and in the second tab send a request to the address send2
OHHHHHHHHH
I get it now
yea I just tried
it
it all makes sense now
thank you sooooooo mcuh
for spending so much time with me
I appreciate it soooo much
lastly
is there a way to force a user to join a room? kinda to replicate how a messaging system would work where you have 1 user create a room to send a message to x person, and the person that receives the message is forced to join that room because they received a message?
bit of a long shot, but I would assume there are ways to replicate this type of behavior
I would also probably assume that this is something that would be done from the UI because the server wouldn't know about x user that received a message
but regardless if you know or care to share thank you so much for the time you spent to help me understand how this all works
maybe this coud be
lets say there are two users in an database user A and user B. User A follows user B and a unique key is generated from this relationship
If user A follows user B via socket connection he can creat an room with this switch If user A is not following user B they should not be allowed to send messages
message from the relationship that user A follows are sent from a room created with the unique key
more details https://socket.io/docs/v4/rooms/
A room is an arbitrary channel that sockets can join and leave. It can be used to broadcast events to a subset of clients:
okay that makes sense
but from a perspective if they both follow each other
and user A sends a message to User B, how would user B get that notification that a message has been sent their messages?
and they are both allowed to message each other, but a conversation was never started
could something potentially be the case where I could do a find all where user B in chat room and make that user join each room that user B is found in?
i am sorry, my brain started burning after writing this🔥
but I found a great resource for you that you should check out
https://github.com/stuyy/chat-platform-nestjs
@brisk oracle and ı have a request if u could reply to my msg by right click and selecting reply and then say thank you after, the bot could see that @opal shore
thank you
also what does the reputation bot even do lol