docs(arch): show Caddy + X-Forwarded-Proto in auth-flow diagram

Adds the Caddy hop to seq-auth-flow.puml and surfaces the two
production-relevant header behaviours:

  - Caddy terminates TLS and forwards X-Forwarded-Proto: https
  - Spring Boot trusts this header (server.forward-headers-strategy:
    native, ForwardedRequestCustomizer at the Jetty layer), so
    request.getScheme() returns "https"
  - The Set-Cookie response carries the Secure flag because the
    observed scheme is https — without forward-headers-strategy this
    would silently drop to plain http and the cookie would lose Secure

Closes the doc-currency gap flagged in the Markus review on PR #499:
"Auth flow change → docs/architecture/c4/seq-auth-flow.puml".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-11 13:17:12 +02:00
parent 6a6a1c4353
commit 03d478840b

View File

@@ -1,26 +1,49 @@
@startuml
title Authentication Flow
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 -> Frontend: POST /login (form action)
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: <client IP>
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 <token>
Frontend -> Backend: GET /api/users/me\nAuthorization: Basic <token>\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 -> Browser: Set-Cookie: auth_token=<base64>\n(httpOnly, SameSite=strict, maxAge=86400)
Browser -> Frontend: GET / (next request)
Frontend -> Caddy: Set-Cookie: auth_token=<base64>\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 <token>
Backend --> Frontend: 200 OK — user in event.locals
Frontend --> Browser: Render page with user context
Frontend --> Caddy: rendered page
Caddy --> Browser: HTTPS 200
@enduml