@startuml title Authentication Flow (behind Caddy reverse proxy) actor User participant Browser participant "Caddy (TLS termination)" as Caddy participant "Frontend (SvelteKit)" as Frontend participant "Backend (Spring Boot)" as Backend participant PostgreSQL as DB User -> Browser: Enter email + password Browser -> Caddy: HTTPS POST /login (form action) note right of Caddy Caddy terminates TLS and forwards to Frontend over HTTP with: X-Forwarded-Proto: https X-Forwarded-For: X-Forwarded-Host: archiv.raddatz.cloud end note Caddy -> Frontend: HTTP POST /login\n+ X-Forwarded-Proto: https Frontend -> Frontend: Base64 encode "email:password" Frontend -> Backend: GET /api/users/me\nAuthorization: Basic \n+ X-Forwarded-Proto: https note right of Backend server.forward-headers-strategy: native Jetty's ForwardedRequestCustomizer reads X-Forwarded-Proto so request.getScheme() returns "https". end note Backend -> Backend: Spring Security parses Basic Auth Backend -> DB: SELECT user WHERE email=? DB --> Backend: AppUser + groups + permissions Backend -> Backend: BCrypt.matches(password, hash) Backend --> Frontend: 200 OK — UserDTO Frontend -> Caddy: Set-Cookie: auth_token=\n(httpOnly, **Secure**, SameSite=strict, maxAge=86400) note right of Frontend Secure flag is set because the request scheme observed by the app is https (forwarded by Caddy). end note Caddy -> Browser: HTTPS 200 + Set-Cookie Browser -> Caddy: HTTPS GET / (next request) Caddy -> Frontend: HTTP GET / + X-Forwarded-Proto: https Frontend -> Frontend: hooks.server.ts reads auth_token cookie Frontend -> Backend: GET /api/users/me\nAuthorization: Basic Backend --> Frontend: 200 OK — user in event.locals Frontend --> Caddy: rendered page Caddy --> Browser: HTTPS 200 @enduml