From 284a5b3f53f706a2bdc9f012e26d2090792c5da0 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Nov 2025 14:41:22 +0000 Subject: [PATCH] docs(api): enhance WebSocket and CORS middleware documentation Update code comments to better explain recent WebSocket-related changes: - CORS middleware: Add comprehensive documentation explaining WebSocket headers required for real-time features (Upgrade, Connection, Sec-WebSocket-Key, etc.) and their purpose in the handshake process - Auth middleware: Document WebSocket-specific error handling that returns status codes only (no JSON body) to maintain protocol compatibility with WebSocket upgrader These comment improvements reflect the recent fixes for WebSocket connections (commits 1c9be1f, 9e02842) and clarify implementation details for future developers. --- api/cmd/main.go | 27 +++++++++++++++++++++++++++ api/internal/auth/middleware.go | 14 +++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/api/cmd/main.go b/api/cmd/main.go index e0a1cf36..d4375be6 100644 --- a/api/cmd/main.go +++ b/api/cmd/main.go @@ -808,6 +808,30 @@ func setupRoutes(router *gin.Engine, h *api.Handler, userHandler *handlers.UserH } } +// corsMiddleware configures Cross-Origin Resource Sharing (CORS) for the API. +// This middleware enables the web UI to communicate with the API backend when they +// are served from different origins (domains/ports). +// +// SECURITY FEATURES: +// - Origin validation: Only explicitly allowed origins can access the API +// - Credential support: Allows cookies and authorization headers in CORS requests +// - WebSocket support: Includes headers required for WebSocket upgrade handshake +// +// WEBSOCKET HEADERS: +// The following headers are essential for WebSocket connections to work: +// - Upgrade: Indicates protocol upgrade from HTTP to WebSocket +// - Connection: Specifies the connection should be upgraded +// - Sec-WebSocket-Key: Client-generated key for handshake +// - Sec-WebSocket-Version: WebSocket protocol version +// - Sec-WebSocket-Extensions: Optional WebSocket extensions +// - Sec-WebSocket-Protocol: Sub-protocol negotiation +// +// CONFIGURATION: +// Set CORS_ALLOWED_ORIGINS environment variable with comma-separated list of origins: +// Example: CORS_ALLOWED_ORIGINS="https://app.streamspace.io,https://admin.streamspace.io" +// +// DEVELOPMENT: +// If not configured, defaults to localhost:3000,8000 for local development func corsMiddleware() gin.HandlerFunc { // SECURITY: Get allowed origins from environment allowedOriginsEnv := getEnv("CORS_ALLOWED_ORIGINS", "") @@ -843,6 +867,9 @@ func corsMiddleware() gin.HandlerFunc { c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") } + // Allow standard HTTP headers plus WebSocket upgrade headers + // WebSocket headers (Upgrade, Connection, Sec-WebSocket-*) are required for + // real-time features like session updates and VNC connections c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With, Upgrade, Connection, Sec-WebSocket-Key, Sec-WebSocket-Version, Sec-WebSocket-Extensions, Sec-WebSocket-Protocol") c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, PATCH, DELETE") diff --git a/api/internal/auth/middleware.go b/api/internal/auth/middleware.go index 63ed3cf7..7f45892e 100644 --- a/api/internal/auth/middleware.go +++ b/api/internal/auth/middleware.go @@ -140,10 +140,22 @@ import ( "github.com/streamspace/streamspace/api/internal/db" ) -// Middleware creates an authentication middleware +// Middleware creates an authentication middleware that validates JWT tokens +// and ensures user accounts are active. +// +// WEBSOCKET HANDLING: +// WebSocket upgrade requests receive special treatment to maintain protocol compatibility: +// - Detected by checking Upgrade=websocket and Connection=Upgrade headers +// - On auth failure: Returns status code only (no JSON body) via AbortWithStatus +// - Rationale: WebSocket upgrader expects clean HTTP responses without body content +// - Standard requests: Returns JSON error messages as usual +// +// This dual-response approach was added to fix WebSocket connection issues where +// JSON error responses would interfere with the WebSocket handshake protocol. func Middleware(jwtManager *JWTManager, userDB *db.UserDB) gin.HandlerFunc { return func(c *gin.Context) { // Check if this is a WebSocket upgrade request + // WebSocket requests need special error handling (status code only, no JSON body) isWebSocket := c.GetHeader("Upgrade") == "websocket" && c.GetHeader("Connection") == "Upgrade" // Extract token from Authorization header