From 530973c475e4a6360e5580e3f6f1b7d4e3c1938c Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 2 Mar 2026 21:52:43 +0100 Subject: [PATCH] fix(auth): make SameSite=None conditional on HTTPS for refresh cookie SameSite=None requires Secure=true per browser spec. When running over plain HTTP (local dev, e2e tests), browsers reject or downgrade the cookie, breaking session refresh. Fall back to SameSite=Lax for HTTP while keeping SameSite=None for HTTPS (needed for the Electron desktop app cross-origin scenario). --- pkg/modules/auth/auth.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/modules/auth/auth.go b/pkg/modules/auth/auth.go index 5dc97cec9..476416695 100644 --- a/pkg/modules/auth/auth.go +++ b/pkg/modules/auth/auth.go @@ -55,6 +55,15 @@ const refreshTokenCookiePath = "/api/v1/user/token/refresh" //nolint:gosec // no // it on refresh requests. HttpOnly prevents JavaScript access (XSS protection). func SetRefreshTokenCookie(c *echo.Context, token string, maxAge int) { secure := strings.HasPrefix(config.ServicePublicURL.GetString(), "https") + // SameSite=None allows cross-origin sending (needed for the Electron + // desktop app where the page is on localhost but the API is remote), + // however browsers require Secure=true for SameSite=None cookies. + // When running over plain HTTP (e.g. local dev or E2E tests), fall + // back to Lax so the cookie is still accepted by the browser. + sameSite := http.SameSiteLaxMode + if secure { + sameSite = http.SameSiteNoneMode + } c.SetCookie(&http.Cookie{ Name: RefreshTokenCookieName, Value: token, @@ -62,7 +71,7 @@ func SetRefreshTokenCookie(c *echo.Context, token string, maxAge int) { MaxAge: maxAge, HttpOnly: true, Secure: secure, - SameSite: http.SameSiteNoneMode, + SameSite: sameSite, }) }