# 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
