From 453c52584c2e406cc84210f973de3758eb2a4d22 Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Tue, 31 Mar 2026 23:13:37 -0700 Subject: [PATCH] Fix SSO cookies not stored on Firefox 302 redirects Firefox does not reliably store Set-Cookie headers on 302 responses that redirect to a different origin. Change RedirectToLogin to return a 200 with an HTML meta-refresh instead, ensuring cookies are stored before navigation. Co-Authored-By: Claude Opus 4.6 (1M context) --- sso/sso.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/sso/sso.go b/sso/sso.go index e0fb6f2..e2d7a79 100644 --- a/sso/sso.go +++ b/sso/sso.go @@ -22,6 +22,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "html" "io" "net/http" "net/url" @@ -268,6 +269,12 @@ func ConsumeReturnToCookie(w http.ResponseWriter, r *http.Request, prefix string // RedirectToLogin generates a state, sets the state and return-to cookies, // and redirects the user to the MCIAS authorize URL. +// +// The redirect is performed via a 200 response with an HTML meta-refresh +// instead of a 302. Some browsers (notably Firefox) do not reliably store +// Set-Cookie headers on 302 responses that redirect to a different origin, +// even when the origins are same-site. Using a 200 response ensures the +// cookies are stored before the browser navigates away. func RedirectToLogin(w http.ResponseWriter, r *http.Request, client *Client, cookiePrefix string) error { state, err := GenerateState() if err != nil { @@ -276,7 +283,15 @@ func RedirectToLogin(w http.ResponseWriter, r *http.Request, client *Client, coo SetStateCookie(w, cookiePrefix, state) SetReturnToCookie(w, r, cookiePrefix) - http.Redirect(w, r, client.AuthorizeURL(state), http.StatusFound) + + authorizeURL := client.AuthorizeURL(state) + escaped := html.EscapeString(authorizeURL) + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.WriteHeader(http.StatusOK) + _, _ = fmt.Fprintf(w, ` + +

Redirecting to MCIAS...

`, + escaped, escaped) return nil }