Mail: Restored Login Protection Behind the Reverse Proxy
Executive summary
A security fix for the Mail application's authentication gate, which had been silently bypassed in the QA environment because of how the app sits behind a Docker/nginx reverse proxy. With this change, the login check correctly identifies the real client-facing domain, so unauthenticated users are once again redirected to single sign-on (SSO) instead of reaching protected pages.
Why this was needed
The Mail app's middleware decides whether a request is "cross-origin" (API domain vs. app domain) to know when to enforce authentication. Behind a reverse proxy, the code read request.nextUrl.hostname, which returns localhost rather than the public domain. That made the app domain look different from the API domain, the check misfired, and authentication enforcement was skipped entirely on QA — leaving routes reachable without a valid session.
Client / user impact
Authentication is enforced again in the affected environment. Unauthenticated visitors to Mail routes (e.g. the inbox) are redirected to SSO login instead of loading protected content. There is no change to behavior for already-authenticated users; the normal login flow (Mail → SSO → back to Mail → inbox) continues to work.
Technical scope
- Single file changed:
apps/mail/src/middleware.ts(+14 / -2). isCrossOrigin()now derives the app hostname from thex-forwarded-hostheader (first value), falling back tohost, then torequest.nextUrl.hostname, instead of relying onnextUrl.hostnamealone.- The resolved host is normalized by stripping any trailing port (e.g.
mail.example.com:443→mail.example.com) before the base-domain comparison, so a forwarded port can no longer break the check. - The
X-Debug-App-Hostresponse header was updated to report the same forwarded/host value for verification.
Risk & mitigation
Low and well-scoped: the change touches only middleware hostname resolution and adds header-based fallbacks rather than altering the auth logic itself. Main residual risk is environment-specific proxy header configuration — if x-forwarded-host is not set or is set incorrectly by the proxy, the comparison could still resolve unexpectedly. Mitigation: verify via the debug headers after deploy, and the layered fallback (forwarded-host → host → nextUrl) preserves prior behavior where headers are absent.
QA validation focus
- Hit a protected Mail route while logged out (e.g. the inbox) and confirm a 307 redirect to SSO, not a 200/page load.
- Confirm debug headers show
x-debug-skip-auth: falseandx-debug-cross-origin: false, and thatX-Debug-App-Hostreflects the real public domain (notlocalhost). - Exercise the full login flow: Mail QA → SSO login → redirect back → inbox loads for an authenticated user.
- Sanity-check a host value that includes a port to confirm the port-stripping works and auth is still enforced.
- Confirm any temporary debug headers are removed once the fix is validated.