Skip to content

[Backend] Add JWT Authentication to Realtime WebSocket Gateway #499

@llinsss

Description

@llinsss

⚠️ This is a backend issue — work is done inside the backend/ folder

Description

backend/src/modules/realtime/realtime.gateway.ts has a comment — // Extract userId from token if auth implemented — in handleConnection(). The gateway currently accepts connections from any client without verifying identity. This means any unauthenticated client can subscribe to any user's file upload and processing events.

Current State

  • backend/src/modules/realtime/realtime.gateway.ts — no auth on connection
  • backend/src/websocket/guards/ws-auth.guard.ts — a WebSocket auth guard exists in the websocket module but is not used in the realtime gateway
  • CORS is set to origin: '*' — acceptable for dev but must be env-driven

What Needs to Be Built

1. Apply WsAuthGuard to RealtimeGateway

@UseGuards(WsAuthGuard)
@WebSocketGateway({ namespace: 'files', cors: { origin: process.env.ALLOWED_ORIGINS } })
export class RealtimeGateway implements OnGatewayConnection, OnGatewayDisconnect {

2. Extract userId on Connection

handleConnection(client: Socket) {
  const token = client.handshake.auth?.token ?? client.handshake.headers?.authorization?.split(' ')[1];
  const payload = this.jwtService.verify(token);
  client.data.userId = payload.sub;
  client.join(`user:${payload.sub}`);
}

3. Scope Subscriptions to Authenticated User

  • subscribe:file — verify the requesting user owns the file before joining the room
  • subscribe:user — only allow joining own user room (prevent subscribing to other users' events)

4. CORS Configuration

  • Replace hardcoded origin: '*' with ALLOWED_ORIGINS env variable
  • Support comma-separated list of origins

5. Unit Tests

  • Test that unauthenticated connections are rejected
  • Test that users cannot subscribe to another user's room

Acceptance Criteria

  • Unauthenticated WebSocket connections are rejected with a 401 disconnect
  • client.data.userId is populated from the JWT on every connection
  • Users can only subscribe to their own user room
  • CORS origin is driven by environment variable
  • Unit tests cover auth rejection and room scoping

Files to Modify

  • backend/src/modules/realtime/realtime.gateway.ts
  • backend/src/modules/realtime/realtime.module.ts (import JwtModule)

Priority

High — unauthenticated access to real-time events is a security vulnerability

Estimated Effort

1–2 days

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions