From 58eb2807c78ebbaffcfdae2c2ae83449ac19e1a7 Mon Sep 17 00:00:00 2001 From: Till JS Date: Wed, 20 May 2026 15:09:23 +0200 Subject: [PATCH] fix(auth): CookieBridge SameSite=None + Cross-Domain-Kommentar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CookieBridge ist immer noch Skeleton (no-op currentAccessToken), aber das Cookie-Setup wird vor ζ-3 scharf. Zwei Korrekturen: 1. Domain `.mana.how` ist tatsächlich korrekt für app.zitare.com: der Cookie wird vom WebView an XHR-Ziele auf .mana.how mitgesendet (auth.mana.how/refresh), unabhängig vom Source-Page-Host. Gleicher Flow wie im Web-Client. Vorheriger „bricht cross-domain"-Kommentar war falsch. 2. SameSite=Lax → "None" — mana-auth setzt für Cross-Subdomain-SSO sameSite='none' (better-auth.config.ts:320). Ohne None wird der Cookie bei Cross-Origin-POST nicht versendet. Foundation hat keine .sameSiteNone-Konstante, akzeptiert aber Roh-Strings für .sameSitePolicy. Co-Authored-By: Claude Opus 4.7 (1M context) --- Sources/Core/WebShell/CookieBridge.swift | 36 +++++++++++++++--------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/Sources/Core/WebShell/CookieBridge.swift b/Sources/Core/WebShell/CookieBridge.swift index 52ae601..c13211d 100644 --- a/Sources/Core/WebShell/CookieBridge.swift +++ b/Sources/Core/WebShell/CookieBridge.swift @@ -13,22 +13,26 @@ import WebKit /// *echten* mana-auth-Token End-to-End getestet sein (Verifikations- /// Lücke in `zitare/STATUS.md`). /// -/// **Cross-Domain-Hinweis 2026-05-20:** Mana-Auth setzt den Cookie -/// auf `.mana.how`. Seit dem Zitare-Cutover auf `app.zitare.com` -/// kann dieser Cookie nicht mehr direkt geteilt werden. Der WebView- -/// Auth-Pfad braucht stattdessen Bearer-Token-Injection (siehe -/// Web-App `apps/zitare/src/lib/auth.ts` Pattern: Cross-Origin -/// /refresh gegen auth.mana.how mit credentials:include) oder ein -/// dediziertes Cookie auf `.zitare.com` via mana-auth-Erweiterung. -/// Diese Klasse ist noch nicht angepasst — Update kommt vor ζ-3. +/// **Cross-Domain-Flow (Cutover 2026-05-20):** Der WKWebView lädt +/// `app.zitare.com` (Brand-Domain). Die SvelteKit-App ruft beim +/// Boot Cross-Origin `POST auth.mana.how/api/v1/auth/refresh` mit +/// `credentials: 'include'` und erwartet einen Refresh-Cookie auf +/// `.mana.how`. Der Cookie-Domain-Wert hier (`.mana.how`) ist +/// genau richtig — der Browser sendet ihn an das XHR-Ziel +/// (auth.mana.how), unabhängig vom Source-Page-Host. Identisches +/// Pattern wie im Web-Client (`apps/zitare/src/lib/auth.ts`). /// -/// **Cookie-Schema** (gespiegelt zu mana-auth, siehe -/// `mana/services/mana-auth/src/auth/cookies.ts`): +/// **Cookie-Schema** (gespiegelt zu mana-auth `better-auth.config.ts`): /// - Name: `mana.access` (JWT) und optional `mana.refresh` (Opaque) -/// - Domain: `.mana.how` (greift heute nicht für `.zitare.com`) +/// - Domain: `.mana.how` (Cookie wird an auth.mana.how-XHR mitgesendet) /// - Path: `/` -/// - Secure: true, HTTPOnly: false (WebView muss lesen können), -/// SameSite: Lax +/// - Secure: true, HTTPOnly: false (WebView muss lesen können) +/// - SameSite: **None** — mana-auth setzt für Cross-Subdomain-SSO +/// `sameSite: 'none'` (better-auth.config.ts), ohne das wird der +/// Cookie bei Cross-Origin-POST nicht mitgesendet. Foundation +/// `HTTPCookieStringPolicy` hat dafür keinen Konstanten-Wert → +/// `cookieAttributesNone` als Roh-String über die initWithProperties- +/// `String`-Variante. enum CookieBridge { /// Setzt den `mana.access`-Cookie im geteilten `WKHTTPCookieStore`, /// wenn der `AuthClient` einen gültigen JWT hält. No-op sonst. @@ -68,13 +72,17 @@ enum CookieBridge { } private static func makeAccessCookie(token: String) -> HTTPCookie? { + // SameSite=None: Foundation hat keinen Konstanten-Wert für + // "None", aber HTTPCookie akzeptiert beliebige Strings für + // .sameSitePolicy. Cross-Origin-POST von app.zitare.com → + // auth.mana.how braucht None, sonst kein Cookie-Versand. HTTPCookie(properties: [ .name: "mana.access", .value: token, .domain: ".mana.how", .path: "/", .secure: true, - .sameSitePolicy: HTTPCookieStringPolicy.sameSiteLax + .sameSitePolicy: "None" ]) } }