package auth import ( "net/http" "time" ) // SetSessionCookie writes an HTTP-only session cookie to the response. // The Secure attribute is gated by the secure parameter — callers pass // (ENV != "dev") so plain localhost works in development (D-12). // // Cookie attributes per D-12: // - HttpOnly: true (no JS access) // - Secure: env-gated // - SameSite: Lax (blocks cross-site POST; allows top-level GET navigation) // - Path: / // - MaxAge: mirrors the session TTL (re-issued on extension so the browser // cookie lifetime stays in sync with the DB row) func SetSessionCookie(w http.ResponseWriter, value string, expiresAt time.Time, secure bool) { maxAge := int(time.Until(expiresAt).Seconds()) if maxAge < 0 { maxAge = 0 } http.SetCookie(w, &http.Cookie{ Name: SessionCookieName, Value: value, Path: "/", Expires: expiresAt, MaxAge: maxAge, HttpOnly: true, Secure: secure, SameSite: http.SameSiteLaxMode, }) } // ClearSessionCookie instructs the browser to delete the session cookie. // MaxAge=-1 in Go's http.Cookie emits "Max-Age=0" in the Set-Cookie header, // which browsers interpret as "delete immediately" (D-06, RESEARCH Pattern 3). func ClearSessionCookie(w http.ResponseWriter, secure bool) { http.SetCookie(w, &http.Cookie{ Name: SessionCookieName, Value: "", Path: "/", Expires: time.Unix(0, 0), MaxAge: -1, HttpOnly: true, Secure: secure, SameSite: http.SameSiteLaxMode, }) }