From 48f8473200edc4ed038cc9df7ee12e0ab97ec159 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 12 Nov 2025 11:30:22 +0000 Subject: [PATCH] Fix router to allow frontend pages without authentication When a request for /login (or any other frontend route) comes in without proper Accept headers (like from curl or some browsers), the server was returning 'Authentication required' text instead of serving the frontend HTML. This is because the router was checking authentication before serving ANY non-API route, including frontend pages like /login, /dashboard, etc. The fix: Frontend routes should always be served without backend auth checks. The authentication logic runs in the frontend JavaScript after the page loads. Backend auth should only block: - API endpoints (/api/*) - WebSocket connections (/ws*, /socket.io/*) - Download endpoints (/download/*) - Special scripts (/install-*.sh, etc.) All other routes are frontend pages that need to be served to everyone so the login page can load and handle auth in the browser. This fixes the integration tests where Playwright couldn't see the login form because the server was rejecting the /login request before serving HTML. Related to #695 (release workflow integration tests) --- internal/api/router.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/internal/api/router.go b/internal/api/router.go index 9bb329a..a48571f 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -1297,6 +1297,19 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { // Also allow static assets without auth (JS, CSS, etc) // These MUST be accessible for the login page to work + // Frontend routes (non-API, non-download) should also be public + // because authentication is handled by the frontend after page load + isFrontendRoute := !strings.HasPrefix(req.URL.Path, "/api/") && + !strings.HasPrefix(req.URL.Path, "/ws") && + !strings.HasPrefix(req.URL.Path, "/socket.io/") && + !strings.HasPrefix(req.URL.Path, "/download/") && + req.URL.Path != "/simple-stats" && + req.URL.Path != "/install-docker-agent.sh" && + req.URL.Path != "/install-container-agent.sh" && + req.URL.Path != "/install-host-agent.sh" && + req.URL.Path != "/install-host-agent.ps1" && + req.URL.Path != "/uninstall-host-agent.ps1" + isStaticAsset := strings.HasPrefix(req.URL.Path, "/assets/") || strings.HasPrefix(req.URL.Path, "/@vite/") || strings.HasPrefix(req.URL.Path, "/@solid-refresh") || @@ -1314,7 +1327,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { strings.HasSuffix(req.URL.Path, ".mjs") || strings.HasSuffix(req.URL.Path, ".jsx") - isPublic := isStaticAsset + isPublic := isStaticAsset || isFrontendRoute for _, path := range publicPaths { if normalizedPath == path { isPublic = true