fix(websocket): enable WebSocket authentication via query parameter#60
Merged
JoshuaAFerguson merged 6 commits intoNov 17, 2025
Merged
Conversation
PROBLEM: - WebSocket connections were failing with authentication errors - Frontend could not establish real-time connections - Users saw "real-time connection error" and lost live updates ROOT CAUSE: - Browser WebSocket API cannot send custom HTTP headers (e.g., Authorization) - Auth middleware only checked Authorization header, which wasn't available - Frontend had token but no way to send it during WebSocket handshake SOLUTION: Backend (api/internal/auth/middleware.go): - Modified auth middleware to accept token from query parameter for WebSocket connections - Maintains backward compatibility with Authorization header for regular HTTP requests - Checks query parameter first for WebSocket upgrades, falls back to header Frontend (ui/src/hooks/useEnterpriseWebSocket.ts): - Updated WebSocket URL to include token as query parameter - Removed redundant token check (now handled in URL construction) - Uses encodeURIComponent for proper URL encoding SECURITY: - Query parameter auth only used for WebSocket upgrade requests - Token still validated with same JWT verification process - No change to security model, just different transport mechanism TESTING: - WebSocket connections should now authenticate successfully - Real-time updates should work (session status, notifications, etc.) - Frontend should show "Real-time updates connected" notification Fixes: WebSocket authentication and real-time connection issues
…WebSocket error dialog - Changed primary button from 'Reload Page' to 'Continue Without Live Updates' - Moved 'Reload Page' to secondary button position - Makes it easier to continue using the app when WebSocket is unavailable - Removes confusing suggestion to try refreshing
- Added 'ws: true' to Vite proxy config for /api route - Fixes NS_ERROR_CONNECTION_REFUSED for WebSocket connections - WebSocket connections were failing because Vite wasn't upgrading HTTP to WS Without this option, Vite proxy blocks WebSocket upgrade requests, causing all WebSocket connections to fail with CONNECTION_REFUSED.
…uthentication PROBLEM: - WebSocket connections for /ws/sessions and /ws/cluster were failing - Connections were trying to reach ws://localhost:8000 directly - Should connect through Vite proxy at ws://localhost:3000 - All WebSocket endpoints require authentication CHANGES: 1. Updated useSessionsWebSocket to use window.location.host (not hardcoded) 2. Updated useMetricsWebSocket to use window.location.host 3. Updated useLogsWebSocket to use window.location.host 4. Added token authentication via query parameter to all three hooks This ensures: - Development: Connects to ws://localhost:3000 → Vite proxy → localhost:8000 - Production: Connects to wss://yourdomain.com directly - All connections authenticated with JWT token from localStorage Previously these hooks used VITE_API_URL environment variable which defaulted to http://localhost:8000, bypassing the Vite proxy entirely.
- Added 'dismissed' state to track if user has dismissed the error - After dismissal, subsequent WebSocket errors are logged to console only - Prevents full-screen error dialog from taking over the screen repeatedly - User can continue using the app without constant interruptions
…sive - Moved reconnection banner from top-center to bottom-left - Changed from warning (filled) to info (outlined) style - Added dismiss button to permanently hide the banner - Made it less visually aggressive so it doesn't block the UI - Users can now continue using the app while WebSocket reconnects
JoshuaAFerguson
pushed a commit
that referenced
this pull request
Nov 17, 2025
The WebSocket reconnection dialog was causing an infinite reconnection loop that made the UI unusable. This was happening because: 1. WebSocket callback functions were being recreated on every render 2. When callbacks changed, the WebSocket hooks saw them as new dependencies 3. This triggered WebSocket disconnection and reconnection 4. State updates from reconnection triggered component re-renders 5. Back to step 1, creating an infinite loop Fixed by: - Using useRef to store WebSocket callbacks in both useWebSocket and useEnterpriseWebSocket hooks - Updating refs when callbacks change instead of recreating connections - Wrapping callbacks in useCallback in Dashboard, SessionViewer, and SharedSessions pages (defense in depth) - Removing callback dependencies from WebSocket connect() functions This ensures that callback changes don't trigger reconnection, breaking the loop and making the UI stable again. Fixes reconnection issues from PRs #60 and #61.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PROBLEM:
ROOT CAUSE:
SOLUTION:
Backend (api/internal/auth/middleware.go):
Frontend (ui/src/hooks/useEnterpriseWebSocket.ts):
SECURITY:
TESTING:
Fixes: WebSocket authentication and real-time connection issues