WebSocket hinter Cloudflare Access — Worker-JWT statt Login-302 (OP-AUTH-1 „Weg 1")
⛔ ZURÜCKGEZOGEN (2026-09-22) — „Weg 1" war eine Fehldiagnose
Der WebSocket lief monatelang problemlos hinter der Allow-Access-App: Cloudflare Access autorisiert den eingeloggten WS am Edge und proxied ihn. Die
302, aus der dieses Dokument schloss, der WS stürbe daran, kam ausschließlich von unauthentifizierten Edge-Probes — nicht vom echten, angemeldeten Browser. Der hier beschriebene Worker-JWT-Gate auf/parties/*(aktiviert überACCESS_TEAM_DOMAIN/ACCESS_AUD) lehnt den authentifizierten WS-Handshake mit401ab (das Access-JWT kommt auf dem WS-Upgrade nicht so an, wie der Gate es erwartet) → er hat die zuvor funktionierende Live-Verbindung kaputt gemacht (Regression, RISK-21). Rückzug (v0.164.1): beide Vars inserver/wrangler.tomlleer → der Gate ist aus → Access bleibt an (Allow = Netz-Gate, Golden Rule gewahrt), der eingeloggte WS verbindet wieder. Kein Edge-Bypass, kein Worker-Gate. Das Dokument bleibt als Lernprotokoll erhalten; der Inhalt unten ist historisch/nicht mehr gültig. Falls echte Worker-seitige WS-Identität je gebraucht wird, muss der Gate so gebaut werden, dass er WS-Upgrades niemals ablehnt (nur normale HTTP-Requests) — und erst nach Beweis am authentifizierten Pfad, nicht an unauth-Probes.
Status: historisch — Code gebaut (v0.163.0), am 2026-09-22 zurückgezogen (s. o.) · Bezug: OP-AUTH-1 · Root-
CLAUDE.md→ Golden Rule „Zero Trust vor Public" ·server/wrangler.toml(ACCESS_TEAM_DOMAIN/ACCESS_AUD) · Zielgruppe: IT-Ops · DevOps · CISO/Security · True North: indirekt — ohne funktionierenden WebSocket zeigt die App keine Live-Daten und beantwortet keine der drei Leitfragen.
Kernaussage. Ein WebSocket hinter einer interaktiven Cloudflare-Access-App stirbt: der unauthentifizierte WS-Upgrade bekommt einen
302→Login, dem ein WebSocket nicht folgen kann („closed before the connection is established") → keine Live-Verbindung → leere App. Lösung (Weg 1): den WS-Pfad/parties/*am Edge per Bypass freigeben (kein 302) und die Access-Identität im Worker selbst prüfen — er verifiziert das Access-JWT (aus demCF_Authorization-Cookie, das der App-Login gesetzt hat) gegen die Team-JWKS und lehnt Unbefugte mit401ab. So bleibt/parties/*Zero-Trust-geschützt (Golden Rule gewahrt), aber der WS bekommt sein101statt eines Redirects.
1. Warum (der Befund)
Per direktem Edge-Probe bestätigt: GET https://app.taktano.com/parties/leitstand-server/leitstand-vest
mit WS-Upgrade-Headern → 302 nach drkv-com.cloudflareaccess.com/.../login (auth_status: NONE).
Ein Browser-WebSocket kann einem 302 nicht folgen → er scheitert still. Die App-Shell lädt (HTML ist
Access-authentifiziert), aber der WS liefert keinen State → „0 Fahrzeuge", Sichten wirken gesperrt — kein
Rollen- oder App-Bug, sondern die Access-Absicherung des WS-Pfads.
2. Was der Code tut (dieser PR)
server/wrangler.toml:ACCESS_TEAM_DOMAIN = "drkv-com.cloudflareaccess.com"·ACCESS_AUD = "ffafb06f…ba6"(bare Hostname; JWT-issmuss exakthttps://<team>.cloudflareaccess.comsein).server/party/leitstand.ts(Worker-fetch): nur für/parties/*und nur produktiv (erkannt am von Cloudflare injiziertencf-ray-Header; lokalwrangler dev/E2E fehlt er → Prüfung übersprungen) wird das Access-JWT verifiziert (verifyAccessJwt: RS256 gegen…/cdn-cgi/access/certs,exp/aud/issgeprüft). Erfolg → verifizierte E-Mail als Audit-Actor (X-Taktano-User); Misserfolg →401.- Bewusst pfad-begrenzt (kleiner Blast-Radius): ein falscher
ACCESS_AUDsperrt höchstens den WS aus, nie die ganze App (HTML/Assets/API bleiben von der Edge-Access-App geschützt).
3. Operator-Schritt: Edge-Bypass für /parties/* (Cloudflare Zero Trust)
Reihenfolge zwingend — erst deployen, dann den Bypass setzen (sonst ist der WS-Pfad kurz ungeschützt):
- Deploy dieses Stands:
npm run deploy(setztACCESS_TEAM_DOMAIN/ACCESS_AUD+ den Worker-JWT-Check). - Cloudflare Zero Trust → Access → Applications → Add an application → Self-hosted:
- Application name:
Taktano WS Bypass - Domain:
app.taktano.com· Path:parties(deckt/parties/*ab; die spezifischere Pfad-App hat Vorrang vor der breitenapp.taktano.com-App). - Policy: Action Bypass, Include Everyone.
- Speichern. (Die bestehende
app.taktano.com-App mit der normalen Allow-Policy bleibt — sie sorgt weiter für den interaktiven Login des App-Roots, der denCF_Authorization-Cookie setzt.)
- Application name:
- Verifizieren (angemeldet im Browser): App neu laden → DevTools-Konsole zeigt keinen WS-Fehler mehr,
echte Daten erscheinen, Administration je Rolle offen. Direkt-Probe: ein WS-Upgrade auf
/parties/*ohne gültige Session →401(nicht mehr302); mit Session →101.
4. Sicherheit / Golden Rule
Der Bypass macht /parties/* am Edge offen — die Zero-Trust-Absicherung übernimmt der Worker (dieselbe
Access-JWT-Prüfung, nur nicht als interaktiver Redirect). Ohne gültiges Access-JWT gibt es 401, kein
Datenleck. Die Golden Rule „Zero Trust vor Public" bleibt gewahrt. Wichtig: den Bypass nie setzen, ohne
dass der Worker mit ACCESS_TEAM_DOMAIN/ACCESS_AUD deployt ist (sonst wäre der WS-Pfad kurz komplett offen).
5. Rollback
Die Bypass-Application in Cloudflare Zero Trust wieder löschen → /parties/* fällt auf den interaktiven
Edge-Access zurück (WS wieder 302/gebrochen, aber sicher). Der Worker-Check schadet dann nicht (er greift nur
noch auf einem nicht mehr erreichbaren Pfad). Optional die beiden Vars in wrangler.toml wieder leeren + deployen.
6. Später (OP-AUTH-1 A-3)
Der verifizierte Better-Auth-/JWT-Claim ersetzt die interim selbst-deklarierte Rolle (Menü) durch eine
verifizierte Rolle — dann trägt derselbe Worker-JWT-Pfad auch die Rollen-Durchsetzung (statt ?rolle=).
↩ Zurück zur Doku-Landkarte · Lesepfade · Register (alle OPs)