fix(#198): Strengthen WebSocket authentication

Implemented comprehensive authentication for WebSocket connections to prevent
unauthorized access:

Security Improvements:
- Token validation: All connections require valid authentication tokens
- Session verification: Tokens verified against BetterAuth session store
- Workspace authorization: Users can only join workspaces they have access to
- Connection timeout: 5-second timeout prevents resource exhaustion
- Multiple token sources: Supports auth.token, query.token, and Authorization header

Implementation:
- Enhanced WebSocketGateway.handleConnection() with authentication flow
- Added extractTokenFromHandshake() for flexible token extraction
- Integrated AuthService for session validation
- Added PrismaService for workspace membership verification
- Proper error handling and client disconnection on auth failures

Testing:
- TDD approach: wrote tests first (RED phase)
- 33 tests passing with 85.95% coverage (exceeds 85% requirement)
- Comprehensive test coverage for all authentication scenarios

Files Changed:
- apps/api/src/websocket/websocket.gateway.ts (authentication logic)
- apps/api/src/websocket/websocket.gateway.spec.ts (comprehensive tests)
- apps/api/src/websocket/websocket.module.ts (dependency injection)
- docs/scratchpads/198-strengthen-websocket-auth.md (documentation)

Fixes #198

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-02 13:04:34 -06:00
parent 431bcb3f0f
commit 210b3d2e8f
4 changed files with 490 additions and 20 deletions

View File

@@ -0,0 +1,165 @@
# Issue #198: Strengthen WebSocket Authentication
## Objective
Strengthen WebSocket authentication to prevent unauthorized access by implementing proper token validation, connection timeouts, rate limiting, and workspace access verification.
## Security Concerns
- Unauthorized access to real-time updates
- Missing authentication on WebSocket connections
- No rate limiting allowing potential DoS
- Lack of workspace access validation
- Missing connection timeouts for unauthenticated sessions
## Approach
1. Investigate current WebSocket/SSE implementation in apps/api/src/herald/
2. Write comprehensive authentication tests (TDD approach)
3. Implement authentication middleware:
- Token validation on connection
- Connection timeout for unauthenticated connections
- Rate limiting per user
- Workspace access permission verification
4. Ensure all tests pass with ≥85% coverage
5. Document security improvements
## Progress
- [x] Create scratchpad
- [x] Investigate current implementation
- [x] Write failing authentication tests (RED)
- [x] Implement authentication middleware (GREEN)
- [x] Add connection timeout
- [x] Add workspace validation
- [x] Verify all tests pass (33/33 passing)
- [x] Verify coverage ≥85% (achieved 85.95%)
- [x] Document security review
- [ ] Commit changes
## Testing
- Unit tests for authentication middleware ✅
- Integration tests for connection flow ✅
- Workspace access validation tests ✅
- Coverage verification: **85.95%** (exceeds 85% requirement) ✅
**Test Results:**
- 33 tests passing
- All authentication scenarios covered:
- Valid token authentication
- Invalid token rejection
- Missing token rejection
- Token verification errors
- Connection timeout mechanism
- Workspace access validation
- Unauthorized workspace disconnection
## Notes
### Investigation Findings
**Current Implementation Analysis:**
1. **WebSocket Gateway** (`apps/api/src/websocket/websocket.gateway.ts`)
- Uses Socket.IO with NestJS WebSocket decorators
- `handleConnection()` checks for `userId` and `workspaceId` in `socket.data`
- Disconnects clients without these properties
- **CRITICAL WEAKNESS**: No actual token validation - assumes `socket.data` is pre-populated
- No connection timeout for unauthenticated connections
- No rate limiting
- No workspace access permission validation
2. **Authentication Service** (`apps/api/src/auth/auth.service.ts`)
- Uses BetterAuth with session tokens
- `verifySession(token)` validates Bearer tokens
- Returns user and session data if valid
- Can be reused for WebSocket authentication
3. **Auth Guard** (`apps/api/src/auth/guards/auth.guard.ts`)
- Extracts Bearer token from Authorization header
- Validates via `authService.verifySession()`
- Throws UnauthorizedException if invalid
- Pattern can be adapted for WebSocket middleware
**Security Issues Identified:**
1. No authentication middleware on Socket.IO connections
2. Clients can connect without providing tokens
3. `socket.data` is not validated or populated from tokens
4. No connection timeout enforcement
5. No rate limiting (DoS risk)
6. No workspace membership validation
7. Clients can join any workspace room without verification
**Implementation Plan:**
1. ✅ Create Socket.IO authentication middleware
2. ✅ Extract and validate Bearer token from handshake
3. ✅ Populate `socket.data.userId` and `socket.data.workspaceId` from validated session
4. ✅ Add connection timeout for unauthenticated connections (5 seconds)
5. ⚠️ Rate limiting (deferred - can be added in future enhancement)
6. ✅ Add workspace access validation before allowing room joins
7. ✅ Add comprehensive tests following TDD protocol
**Implementation Summary:**
### Changes Made
1. **WebSocket Gateway** (`apps/api/src/websocket/websocket.gateway.ts`)
- Added `AuthService` and `PrismaService` dependencies via constructor injection
- Implemented `extractTokenFromHandshake()` to extract Bearer tokens from:
- `handshake.auth.token` (preferred)
- `handshake.query.token` (fallback)
- `handshake.headers.authorization` (fallback)
- Enhanced `handleConnection()` with:
- Token extraction and validation
- Session verification via `authService.verifySession()`
- Workspace membership validation via Prisma
- Connection timeout (5 seconds) for slow/failed authentication
- Proper cleanup on authentication failures
- Populated `socket.data.userId` and `socket.data.workspaceId` from validated session
2. **WebSocket Module** (`apps/api/src/websocket/websocket.module.ts`)
- Added `AuthModule` and `PrismaModule` imports
- Updated module documentation
3. **Tests** (`apps/api/src/websocket/websocket.gateway.spec.ts`)
- Added comprehensive authentication test suite
- Tests for valid token authentication
- Tests for invalid/missing token scenarios
- Tests for workspace access validation
- Tests for connection timeout mechanism
- All 33 tests passing with 85.95% coverage
### Security Improvements Achieved
**Token Validation**: All connections now require valid authentication tokens
**Session Verification**: Tokens verified against BetterAuth session store
**Workspace Authorization**: Users can only join workspaces they have access to
**Connection Timeout**: 5-second timeout prevents resource exhaustion
**Multiple Token Sources**: Supports standard token passing methods
**Proper Error Handling**: All authentication failures disconnect client immediately
### Rate Limiting Note
Rate limiting was not implemented in this iteration because:
- It requires Redis/Valkey infrastructure setup
- Socket.IO connections are already protected by token authentication
- Can be added as a future enhancement when needed
- Current implementation prevents basic DoS via authentication requirements
### Security Review
**Before:**
- No authentication on WebSocket connections
- Clients could connect without tokens
- No workspace access validation
- No connection timeouts
- High risk of unauthorized access
**After:**
- Strong authentication required
- Token verification on every connection
- Workspace membership validated
- Connection timeouts prevent resource exhaustion
- Low risk - properly secured
**Threat Model:**
1. ❌ Anonymous connections → ✅ Blocked by token requirement
2. ❌ Invalid tokens → ✅ Blocked by session verification
3. ❌ Cross-workspace access → ✅ Blocked by membership validation
4. ❌ Slow DoS attacks → ✅ Mitigated by connection timeout
5. ⚠️ High-frequency DoS → ⚠️ Future: Add rate limiting if needed