diff --git a/playwright.go b/playwright.go index df8fb4b..684c81a 100644 --- a/playwright.go +++ b/playwright.go @@ -219,11 +219,35 @@ func (b playWrightBrowser) updateCookies(_ context.Context, page playwright.Page return fmt.Errorf("error getting cookies from browser: %w", err) } + // Build a lookup of existing cookies so we can preserve their security + // attributes. Chromium's Cookies() API can lose or normalize Secure, + // SameSite, and HttpOnly during the AddCookies → navigate → Cookies() + // round-trip, so we only update Value and Expires for cookies that + // already exist in the jar. + existing, err := b.cookieJar.Get(page.URL()) + if err != nil { + return fmt.Errorf("error getting existing cookies from jar: %w", err) + } + type cookieKey struct{ Name, Path string } + existingMap := make(map[cookieKey]Cookie, len(existing)) + for _, c := range existing { + existingMap[cookieKey{c.Name, c.Path}] = c + } + for _, cookie := range cookies { // TODO: add support for deleting cookies from the jar which are deleted in the browser - err = b.cookieJar.Set(playwrightCookieToCookie(cookie)) + c := playwrightCookieToCookie(cookie) - if err != nil { + if prev, ok := existingMap[cookieKey{c.Name, c.Path}]; ok { + // Preserve the original security attributes; only update + // Value and Expires which are the fields that legitimately + // change during navigation. + c.Secure = prev.Secure + c.HttpOnly = prev.HttpOnly + c.SameSite = prev.SameSite + } + + if err = b.cookieJar.Set(c); err != nil { return fmt.Errorf("error setting cookie in cookie jar: %w", err) } }