diff --git a/auth/middleware.go b/auth/middleware.go index 8416191..cd0c4a4 100644 --- a/auth/middleware.go +++ b/auth/middleware.go @@ -10,9 +10,18 @@ type contextKey string const UserContextKey contextKey = contextKey("user") +// middleware.go func AuthMiddleware(secret []byte) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + // WICHTIG: Wenn der User auf einer öffentlichen Seite ist, + // darf die Middleware KEINEN Auth-Zwang ausüben und nicht redirecten! + if r.URL.Path == "/login" || r.URL.Path == "/register" || r.URL.Path == "/" { + next.ServeHTTP(w, r) + return + } + tokenStr := "" authHeader := r.Header.Get("Authorization") @@ -37,22 +46,25 @@ func AuthMiddleware(secret []byte) func(http.Handler) http.Handler { } claims, err := ValidateJWT(tokenStr, secret) - if err != nil { if strings.HasPrefix(r.URL.Path, "/api/") { http.Error(w, "Invalid token", http.StatusUnauthorized) } else { + // Falls das Cookie korrupt oder abgelaufen ist, löschen wir es direkt, + // damit das Frontend sauber merkt, dass es weg ist. + http.SetCookie(w, &http.Cookie{ + Name: "access_token", + Value: "", + Path: "/", + MaxAge: -1, + HttpOnly: false, // Erlaubt JS das Auslesen + }) http.Redirect(w, r, "/login", http.StatusSeeOther) } return } - ctx := context.WithValue( - r.Context(), - UserContextKey, - claims, - ) - + ctx := context.WithValue(r.Context(), UserContextKey, claims) next.ServeHTTP(w, r.WithContext(ctx)) }) } diff --git a/frontend/assets/js/auth.js b/frontend/assets/js/auth.js index a844166..9231eea 100644 --- a/frontend/assets/js/auth.js +++ b/frontend/assets/js/auth.js @@ -14,17 +14,19 @@ } function clearAllAuth() { - console.log("Clearing all auth remnants from cookies and localStorage..."); + console.log("Clearing all auth remnants from everywhere..."); localStorage.removeItem("access_token"); localStorage.removeItem("refresh_token"); - document.cookie = "access_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;"; - document.cookie = "refresh_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;"; + sessionStorage.removeItem("is_refreshing"); + document.cookie = "access_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC; Secure; SameSite=Lax;"; + document.cookie = "refresh_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC; Secure; SameSite=Lax;"; } async function tryTokenRefresh(refreshToken) { if (!refreshToken) return false; try { + console.log("Sending refresh token to /api/refresh..."); const response = await fetch("/api/refresh", { method: "POST", headers: { "Content-Type": "application/json" }, @@ -33,13 +35,10 @@ if (response.ok) { const data = await response.json(); - localStorage.setItem("access_token", data.access_token); localStorage.setItem("refresh_token", data.refresh_token); - document.cookie = `access_token=${data.access_token}; path=/; max-age=900; SameSite=Lax; Secure`; document.cookie = `refresh_token=${data.refresh_token}; path=/; max-age=604800; SameSite=Lax; Secure`; - return true; } } catch (err) { @@ -59,52 +58,71 @@ const refreshToken = cookieRefreshToken || localRefreshToken; console.log("Auth check started..."); - console.log("AccessToken present:", !!accessToken); - console.log("RefreshToken present:", !!refreshToken); + console.log("AccessToken available (Cookie/Local):", !!cookieAccessToken, "/", !!localAccessToken); + console.log("RefreshToken available (Cookie/Local):", !!cookieRefreshToken, "/", !!localRefreshToken); if (!accessToken && !refreshToken) { - console.log("No tokens found. User is guest."); + console.log("No tokens found in cookies or localStorage. User is a guest."); return; } if (accessToken) { try { - console.log("Attempting ping with access token..."); - const response = await fetch("/api/ping", { + console.log("Validating token against /api/userinfo..."); + + const response = await fetch("/api/userinfo", { method: "GET", headers: { "Authorization": `Bearer ${accessToken}` } }); if (response.ok) { - console.log("Ping successful! Redirecting to dashboard..."); + console.log("Token is perfectly valid!"); + sessionStorage.removeItem("is_refreshing"); + + if (!cookieAccessToken) { + document.cookie = `access_token=${accessToken}; path=/; max-age=900; SameSite=Lax; Secure`; + } + if (!cookieRefreshToken && localRefreshToken) { + document.cookie = `refresh_token=${localRefreshToken}; path=/; max-age=604800; SameSite=Lax; Secure`; + } + + console.log("Redirecting to dashboard..."); window.location.href = "/dashboard"; return; } else { - console.log("Ping failed. Token might be expired. Status:", response.status); + console.log("Token rejected by /api/userinfo. Status:", response.status); } } catch (err) { - console.error("Network error during ping:", err); + console.error("Network error during token verification:", err); } } + if (sessionStorage.getItem("is_refreshing") === "true") { + console.warn("Loop protection triggered! Tokens appear to be corrupt. Clearing storage."); + clearAllAuth(); + return; + } + if (refreshToken) { - console.log("Starting token refresh to rebuild cookies..."); + console.log("Access token has expired. Starting refresh process..."); + sessionStorage.setItem("is_refreshing", "true"); + const refreshSuccessful = await tryTokenRefresh(refreshToken); if (refreshSuccessful) { - console.log("Refresh successful! Redirecting to dashboard..."); - window.location.href = "/dashboard"; + console.log("Refresh successful! Reloading page to apply cookies..."); + window.location.reload(); return; } else { - console.log("Refresh failed. Refresh token is invalid/expired."); + console.log("Refresh failed. Refresh token has also expired."); } } else { - console.log("No refresh token present."); + console.log("No refresh token available for recovery."); } clearAllAuth(); - console.log("Authentication completely failed. Staying on current guest page."); + console.log("Authentication completely failed. User remains on login page."); } - checkAuth(); + setTimeout(checkAuth, 50); })(); \ No newline at end of file diff --git a/handlers/account.go b/handlers/account.go index 5d2fb09..b73902e 100644 --- a/handlers/account.go +++ b/handlers/account.go @@ -268,6 +268,8 @@ func UserInfo(w http.ResponseWriter, r *http.Request) { if err != nil { log.Println("GET [api/userinfo] " + r.RemoteAddr + ": " + err.Error()) + http.Error(w, "Unauthorized: Invalid or expired token", http.StatusUnauthorized) + return } idParam = claims.UserID diff --git a/server/server.go b/server/server.go index 886069b..d1fed6b 100644 --- a/server/server.go +++ b/server/server.go @@ -85,6 +85,7 @@ func (this *Server) Run() { mux.HandleFunc("/api/refresh", handlers.RefreshToken) mux.Handle("/api/logout", auth.AuthMiddleware(this.JWTSecret)(http.HandlerFunc(handlers.Logout))) mux.Handle("/api/profile", auth.AuthMiddleware(this.JWTSecret)(http.HandlerFunc(handlers.UserInfo))) + mux.HandleFunc("/api/userinfo", handlers.UserInfo) if this.AllowRegistration { mux.HandleFunc("/api/register", handlers.APIRegister) }