# Erfaring: Multi-subdomain med SvelteKit (mars 2026) ## Kontekst Innføring av `adm.synops.no` som admin-domene ved siden av `ws.synops.no` (app) avslørte flere arkitekturelle blindsoner. ## Problemer vi møtte ### 1. ORIGIN låser hostname **Symptom:** `event.url.hostname` returnerte alltid `ws.synops.no` uansett hvilken Host-header som kom inn. **Årsak:** `ORIGIN=https://ws.synops.no` i `.env`. SvelteKit adapter-node bruker ORIGIN for å konstruere `event.url` — den *overskriver* Host-headeren. **Løsning:** Fjern ORIGIN. `AUTH_TRUST_HOST=true` lar SvelteKit lese hostname fra selve HTTP Host-headeren. **Læring:** ORIGIN er ment for single-origin deployments. Multi-subdomain krever at SvelteKit leser Host dynamisk. ### 2. Session-cookie bundet til ett subdomain **Symptom:** Login på `ws.synops.no` ga ikke tilgang til `adm.synops.no`. Brukeren ble bedt om å logge inn igjen. **Årsak:** Session-cookie var satt med `domain=ws.synops.no` (default). Cookien var ikke tilgjengelig for `adm.synops.no`. **Løsning:** Sett cookie-domene til `.synops.no` i auth.ts. Alle subdomener deler sesjonen. **Læring:** Wildcard cookie-domene (`.synops.no`) er nødvendig når flere subdomener trenger samme autentisering. Det er trygt så lenge alle subdomener er under vår kontroll. ### 3. CSRF cross-origin blokkering **Symptom:** `Cross-site POST form submissions are forbidden` ved login-callback fra Authentik. **Årsak:** SvelteKit sin innebygde CSRF-sjekk sammenligner request origin mot ORIGIN-variabelen. POST fra `adm.synops.no` til OIDC-callback ble blokkert. **Løsning:** `csrf: { checkOrigin: false }` i svelte.config.js. Trygt fordi OIDC bruker PKCE + state som CSRF-beskyttelse. **Læring:** SvelteKit sin CSRF-sjekk er for streng for multi-origin. Deaktiver den når du har egen CSRF-mekanisme. ### 4. Authentik redirect URI **Symptom:** OIDC-callback feilet fordi `adm.synops.no` ikke var registrert som gyldig redirect URI. **Årsak:** Bare `ws.synops.no` var registrert i Authentik. **Løsning:** Legg til `adm.synops.no/auth/callback/authentik` i Authentik sin provider-konfig. **Læring:** Hvert subdomain trenger egen redirect URI i OIDC. ### 5. TLS-sertifikat **Ikke et problem:** Caddy henter automatisk sertifikat for nye domener via Let's Encrypt ACME. `adm.synops.no` fikk sertifikat i løpet av sekunder ved første request. **Læring:** Caddy sin auto-TLS er utmerket for nye subdomener. Bare legg til i Caddyfile og restart. ## Arkitekturprinsipper vi trekker ut ### 1. Ikke hardkod hostnames i konfigfiler ORIGIN, cookie-domene, redirect URIs — alt som binder til et spesifikt hostname gjør multi-subdomain vanskelig. Foretrekk dynamisk host-deteksjon (`AUTH_TRUST_HOST=true`). ### 2. Cookies på toppdomenet for relaterte subdomener Når flere subdomener trenger samme sesjon, sett cookie på `.synops.no`. CSRF-token kan forbli host-bound (`__Host-` prefix) for ekstra sikkerhet. ### 3. Samme SvelteKit-instans for alle subdomener Ikke kjør separate SvelteKit-instanser per subdomain. Én instans som leser hostname og tilpasser seg. Enklere deploy, delt kodebase, felles sesjon. ### 4. Caddy gjør routing, SvelteKit gjør logikk Caddy ruter domene → SvelteKit. SvelteKit sjekker hostname og tilpasser innhold. Caddy trenger ingen hostname-logikk utover reverse proxy. ## Hva ble gjort riktig - **Caddy-konfig:** Enkelt å legge til nytt subdomain - **Delt SvelteKit:** Ingen duplisert kode - **Cookie-wildcard:** Riktig for relaterte subdomener - **AUTH_TRUST_HOST:** Fungerer godt uten ORIGIN ## Hva vi tenderer til å glemme - **ORIGIN-variabelen** — den overstyrer alt. Sjekk den først. - **Cookie-domene** — default er gjeldende hostname, ikke parent. - **OIDC redirect URIs** — må oppdateres for hvert nytt domene. - **Be bruker slette cookies** — gammel cookie fra ett domene kræsjer med ny cookie fra wildcard-domenet. ## Sjekkliste for nytt subdomain 1. DNS A-record (Hetzner DNS Console) 2. Caddy-blokk i Caddyfile (auto-TLS) 3. Authentik redirect URI 4. Verifiser at ORIGIN *ikke* er satt (eller er kompatibel) 5. Verifiser cookie-domene (`.synops.no`) 6. Test: login → callback → riktig side 7. Be bruker slette cookies hvis problemer