# Put ThothII behind Caddy Choose exactly one authentication mode. Direct ThothII-managed OIDC and deprecated upstream authentication are mutually exclusive proxy contracts; never combine their directives. ## Direct ThothII-managed OIDC Use this mode when `auth.yaml` has `mode: oidc`. Caddy terminates TLS and proxies every request to `frontend`; ThothII performs login, callback validation, session creation, and authorization. Caddy must not apply `forward_auth` or another external authentication gateway. The public `/api/auth/oidc/login` and `/api/auth/oidc/callback` paths pass unchanged through the same proxy as the rest of `/api`. The configured `publicUrl` must match the browser origin. ```caddyfile thoth.example.invalid { reverse_proxy 127.0.0.1:8080 { # No URI rewrite: OIDC login and callback paths reach frontend unchanged. flush_interval -1 header_up Host {host} header_up X-Forwarded-Proto https header_up X-Forwarded-Host {host} } log { output file /var/log/caddy/thoth-access.log format json } } ``` After reload, run Workspace Validate for static validation, `tht auth check` for live, non-interactive authentication diagnosis, and then Workspace Test for aggregate live validation. ## Deprecated upstream migration mode Use this section only while the installation explicitly uses deprecated `upstream` mode. Do not use it with `mode: oidc` or `mode: local`. Here an external authentication gateway owns login and Caddy applies `forward_auth` before forwarding normalized private identity headers to `frontend`. Forwarding identity headers alone does not authenticate a user. The authentication gateway returns 2xx only after validating its own credential or session. Clear browser-supplied public and trusted headers before the subrequest, and map identity only from the successful auth response. ```caddyfile thoth.example.invalid { route { request_header -X-Authenticated-User request_header -X-Thoth-Principal-Issuer request_header -X-Thoth-Principal-Subject request_header -X-Thoth-Principal-Display-Name request_header -X-Thoth-Is-Admin request_header -X-Thoth-Trusted-Principal-Issuer request_header -X-Thoth-Trusted-Principal-Subject request_header -X-Thoth-Trusted-Principal-Display-Name request_header -X-Thoth-Trusted-Is-Admin forward_auth auth-gateway:4180 { uri /verify copy_headers { X-Thoth-Principal-Issuer>X-Thoth-Trusted-Principal-Issuer X-Thoth-Principal-Subject>X-Thoth-Trusted-Principal-Subject X-Thoth-Principal-Display-Name>X-Thoth-Trusted-Principal-Display-Name X-Thoth-Is-Admin>X-Thoth-Trusted-Is-Admin } } reverse_proxy 127.0.0.1:8080 { flush_interval -1 header_up Host {host} header_up X-Forwarded-Proto https } } } ``` ## Trust boundary Caddy is the only public listener and proxies only to loopback `frontend`, never directly to `core`. Configure access logs to omit cookies, authorization data, query strings, and identity headers. Keep Caddy keys and state outside ThothII source and operator directories. ## Validate and reload Keep the public firewall closed while validating: ```sh curl --fail http://127.0.0.1:8080/health caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile sudo systemctl reload caddy ``` ## Test authentication and SSE For direct OIDC, verify the login path redirects to the configured provider, the callback reaches ThothII unchanged, forged identity headers grant nothing, and SSE is unbuffered. For deprecated upstream mode, additionally verify the external gateway rejects unauthenticated traffic and only its 2xx response can create trusted identity headers.