diff --git a/dashcaddy-api/src/utilities/middleware.js b/dashcaddy-api/src/utilities/middleware.js index e7ec8b8..2f5b547 100644 --- a/dashcaddy-api/src/utilities/middleware.js +++ b/dashcaddy-api/src/utilities/middleware.js @@ -274,10 +274,22 @@ module.exports = function configureMiddleware(app, { ); } + // COOKIE-ONLY session validation. The previous IP-keyed cache (verifyIPSession + // + the write-back in this function) caused cross-subdomain SSO breakage when + // Caddy on --network host forwards auth to the container: req.ip arrives as + // 100.121.150.22 (DNS2's tailnet IP) instead of the user's real IP, so the + // IP cache misses even when the cookie is valid. The cookie is signed with a + // persisted HMAC key (loadOrCreateKey()), scoped to .sami via Domain attr, + // HttpOnly + Secure + SameSite=Lax — it's a stronger credential than the IP + // cache. Ref: skill auth-and-monitoring-pitfalls.md "TOTP session validation + // IP-key issue" (FIXED 2026-07-21). function isSessionValid(req) { - if (verifyIPSession(req)) return true; const cookies = parseCookies(req.headers.cookie); if (verifySessionCookie(cookies[SESSION_COOKIE_NAME])) { + // Re-warm the IP cache as a no-op-only fast path (kept for backwards + // compat with code that reads ctx.session.ipSessions.size for telemetry, + // but it is NOT consulted for auth decisions). The next line intentionally + // does NOT gate the return on verifyIPSession anymore. const ip = getClientIP(req); if (totpConfig.sessionDuration && SESSION_DURATIONS[totpConfig.sessionDuration]) { ipSessions.set(ip, { exp: Date.now() + SESSION_DURATIONS[totpConfig.sessionDuration] });