fix(mana-auth): read PUBLIC_*_URL from window-injected vars, not $env/dynamic/public

Pre-deploy-Audit gefunden: meine neue session.svelte.ts + portal-redirect.ts
lasen PUBLIC_MANA_AUTH_URL/PUBLIC_AUTH_WEB_URL via $env/dynamic/public. In
Production ist das aber die Docker-interne URL `http://mana-auth:3001`,
die der Browser nicht erreichen kann — Folge wäre endlose Redirect-Loop
bei der ersten User-Session.

managarten hat das Pattern schon gelöst: hooks.server.ts injiziert
`window.__PUBLIC_*_URL__` aus den `_CLIENT`-suffixed env-Vars (Public-
Domain-Werte). `lib/data/scope/auth-fetch.authBaseUrl()` ist der
kanonische Helper dafür.

- session.svelte.ts: ruft jetzt `authBaseUrl()` aus auth-fetch.
- portal-redirect.ts: eigenes window/process-Lookup für PUBLIC_AUTH_WEB_URL,
  gleiches Pattern.
- hooks.server.ts: PUBLIC_AUTH_WEB_URL_CLIENT-Lesen + window-Injection.
- docker-compose.macmini.yml (mana-app-web): PUBLIC_AUTH_WEB_URL +
  PUBLIC_AUTH_WEB_URL_CLIENT env-Vars hinzugefügt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-05-12 17:05:28 +02:00
parent b299a4acf1
commit dd2e4b6e9f
4 changed files with 41 additions and 9 deletions

View file

@ -27,6 +27,8 @@ import { setSecurityHeaders } from '@mana/shared-utils/security-headers';
const PUBLIC_MANA_AUTH_URL_CLIENT =
process.env.PUBLIC_MANA_AUTH_URL_CLIENT || process.env.PUBLIC_MANA_AUTH_URL || '';
const PUBLIC_AUTH_WEB_URL_CLIENT =
process.env.PUBLIC_AUTH_WEB_URL_CLIENT || process.env.PUBLIC_AUTH_WEB_URL || '';
const PUBLIC_GLITCHTIP_DSN = process.env.PUBLIC_GLITCHTIP_DSN || '';
const PUBLIC_SYNC_SERVER_URL_CLIENT =
@ -227,6 +229,7 @@ export const handle: Handle = async ({ event, resolve }) => {
transformPageChunk: ({ html }) => {
const envScript = `<script>
window.__PUBLIC_MANA_AUTH_URL__ = ${JSON.stringify(PUBLIC_MANA_AUTH_URL_CLIENT)};
window.__PUBLIC_AUTH_WEB_URL__ = ${JSON.stringify(PUBLIC_AUTH_WEB_URL_CLIENT)};
window.__PUBLIC_SYNC_SERVER_URL__ = ${JSON.stringify(PUBLIC_SYNC_SERVER_URL_CLIENT)};
window.__PUBLIC_ULOAD_SERVER_URL__ = ${JSON.stringify(PUBLIC_ULOAD_SERVER_URL_CLIENT)};
window.__PUBLIC_MANA_MEDIA_URL__ = ${JSON.stringify(PUBLIC_MANA_MEDIA_URL_CLIENT)};

View file

@ -6,20 +6,33 @@
* User auf `/auth/callback?next=…`, wo der Token via SSO-Cookie geholt
* und der Encryption-Vault entsperrt wird.
*
* In Dev: `PUBLIC_AUTH_WEB_URL=http://localhost:3002`.
* In Prod: `PUBLIC_AUTH_WEB_URL=https://auth.mana.how`.
*
* Diese Funktion macht einen harten `window.location.href` keinen
* SvelteKit-`goto` weil das Portal eine eigene Origin ist.
*
* Resolution-Order für die Portal-URL:
* 1. `window.__PUBLIC_AUTH_WEB_URL__` (SSR-injected, prod: `https://auth.mana.how`)
* 2. `process.env.PUBLIC_AUTH_WEB_URL` (SSR)
* 3. `https://auth.mana.how` (default auch in localhost ungewöhnlich)
*
* Wie bei `auth-fetch.authBaseUrl` lesen wir NICHT direkt
* `$env/dynamic/public` die Build-Time-Env in Production wäre evtl.
* eine Docker-interne URL.
*/
import { env as publicEnv } from '$env/dynamic/public';
import { browser } from '$app/environment';
const FALLBACK_PORTAL = 'https://auth.mana.how';
const APP_ID = 'mana';
function portalUrl(): string {
return publicEnv.PUBLIC_AUTH_WEB_URL ?? FALLBACK_PORTAL;
if (browser && typeof window !== 'undefined') {
const injected = (window as unknown as { __PUBLIC_AUTH_WEB_URL__?: string })
.__PUBLIC_AUTH_WEB_URL__;
return (injected || FALLBACK_PORTAL).replace(/\/$/, '');
}
const fromEnv =
(typeof process !== 'undefined' && process.env?.PUBLIC_AUTH_WEB_URL) || FALLBACK_PORTAL;
return fromEnv.replace(/\/$/, '');
}
function appOrigin(): string {

View file

@ -30,15 +30,24 @@
* Session vorhält.
*/
import { env as publicEnv } from '$env/dynamic/public';
import { authBaseUrl as resolveAuthBaseUrl } from '$lib/data/scope/auth-fetch';
const TOKEN_KEY = 'mana.auth.accessToken';
const USER_KEY = 'mana.auth.user';
const FALLBACK_AUTH_URL = 'https://auth.mana.how';
/**
* Mana-Auth-API-URL.
*
* Resolution-Order (siehe `auth-fetch.authBaseUrl`):
* 1. `window.__PUBLIC_MANA_AUTH_URL__` (SSR-injected, prod: `https://auth.mana.how`)
* 2. `process.env.PUBLIC_MANA_AUTH_URL` (SSR)
* 3. `http://localhost:3001` (dev fallback)
*
* KEIN `$env/dynamic/public` direkt die Build-Time-Env in Production
* ist `http://mana-auth:3001` (Docker-internal, vom Browser unerreichbar).
*/
function authBaseUrl(): string {
return publicEnv.PUBLIC_MANA_AUTH_URL ?? FALLBACK_AUTH_URL;
return resolveAuthBaseUrl();
}
export interface SessionUser {

View file

@ -895,6 +895,13 @@ services:
PORT: 5000
PUBLIC_MANA_AUTH_URL: http://mana-auth:3001
PUBLIC_MANA_AUTH_URL_CLIENT: https://auth.mana.how
# Auth-Portal-UI (mana-auth-web). In Prod gleiche Origin wie
# mana-auth API — nginx splittet `/api/*` (mana-auth) von den
# UI-Routen `/login`, `/register`, `/auth/callback` (mana-auth-web).
# Client-Code liest die `_CLIENT`-Variante via hooks.server.ts
# injection (`window.__PUBLIC_AUTH_WEB_URL__`).
PUBLIC_AUTH_WEB_URL: https://auth.mana.how
PUBLIC_AUTH_WEB_URL_CLIENT: https://auth.mana.how
PUBLIC_SYNC_SERVER_URL: http://mana-sync:3010
PUBLIC_SYNC_SERVER_URL_CLIENT: https://sync.mana.how
# Unified Hono/Bun API server (apps/api) — hosts all 16 product