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" ]) } }