auth: fix HTTP login loop (Secure=false default, gate dashboard flash)

This commit is contained in:
Ivo Oskamp 2026-05-28 16:26:32 +02:00
parent ed3c080976
commit 2923f350f8
4 changed files with 40 additions and 11 deletions

View File

@ -1,28 +1,44 @@
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Auth gate: runs before the main app IIFE bootstraps. If the user is not // Auth gate: must complete before the main app IIFE renders. While the
// authenticated, we redirect to /login.html (or /setup.html when the backend // gate is in flight, `<html data-auth-pending>` hides the UI via CSS so the
// indicates the initial setup is still required) and abort further init. // dashboard never flashes for an unauthenticated user.
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
(async function authGate() { document.documentElement.dataset.authPending = '1';
window.__authReady = (async function authGate() {
try { try {
const r = await fetch('/api/auth/me', { credentials: 'same-origin' }); const r = await fetch('/api/auth/me', { credentials: 'same-origin' });
if (r.status === 401) { if (r.status === 401) {
const setup = await fetch('/api/auth/setup-required').then(function (x) { return x.json(); }).catch(function () { return { setup_required: false }; }); const setup = await fetch('/api/auth/setup-required').then(function (x) { return x.json(); }).catch(function () { return { setup_required: false }; });
window.location.replace(setup.setup_required ? '/setup.html' : '/login.html'); window.location.replace(setup.setup_required ? '/setup.html' : '/login.html');
return; return false;
}
if (!r.ok) {
window.location.replace('/login.html');
return false;
} }
if (!r.ok) return;
const me = await r.json(); const me = await r.json();
window.__clearviewUser = me; window.__clearviewUser = me;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () { applyAuthUi(me); }, { once: true });
} else {
applyAuthUi(me);
}
delete document.documentElement.dataset.authPending;
return true;
} catch (e) {
window.location.replace('/login.html');
return false;
}
})();
function applyAuthUi(me) {
renderUserBadge(me); renderUserBadge(me);
if (me.role !== 'admin') { if (me.role !== 'admin') {
const usersLink = document.querySelector('[data-route="users"]'); const usersLink = document.querySelector('[data-route="users"]');
if (usersLink) usersLink.style.display = 'none'; if (usersLink) usersLink.style.display = 'none';
} }
} catch (e) {
window.location.replace('/login.html');
} }
})();
function renderUserBadge(me) { function renderUserBadge(me) {
const slot = document.getElementById('userBadge'); const slot = document.getElementById('userBadge');

View File

@ -753,6 +753,11 @@ strong {
} }
} }
/* Hide the SPA until the auth gate resolves prevents the unauthenticated
dashboard flash before the redirect kicks in. Login/setup pages don't load
app.js, so they are unaffected. */
html[data-auth-pending] body { visibility: hidden; }
/* === Auth (login / setup) pages and header badge ============================== */ /* === Auth (login / setup) pages and header badge ============================== */
.auth-page { .auth-page {
display: flex; align-items: center; justify-content: center; display: flex; align-items: center; justify-content: center;

View File

@ -39,5 +39,7 @@ SCAN_MAX_ITEMS_PER_LIST = _int_env("SCAN_MAX_ITEMS_PER_LIST", 10000)
# Auth cookie settings (override via env) # Auth cookie settings (override via env)
COOKIE_NAME = "clearview_session" COOKIE_NAME = "clearview_session"
COOKIE_SECURE = os.environ.get("COOKIE_SECURE", "true").lower() != "false" # Local-only HTTP deployment: default to non-Secure cookies. Set
# COOKIE_SECURE=true if the stack ever sits behind HTTPS.
COOKIE_SECURE = os.environ.get("COOKIE_SECURE", "false").lower() == "true"
COOKIE_SAMESITE = "lax" COOKIE_SAMESITE = "lax"

View File

@ -2,6 +2,12 @@
This file documents changes on the develop branch of this project. This file documents changes on the develop branch of this project.
## 2026-05-28 — Authentication: fix login loop on HTTP-only deployment
### Changed
- `COOKIE_SECURE` now defaults to `false` (the stack runs HTTP-only locally; with `Secure` set, browsers silently drop the session cookie and the user enters a redirect loop). Set `COOKIE_SECURE=true` if the stack is ever fronted by HTTPS.
- SPA boot now hides the dashboard until `/api/auth/me` resolves (via `html[data-auth-pending]` + body visibility), eliminating the brief dashboard flash that appeared before the redirect.
## 2026-05-28 — Authentication: align login/setup/modal styling with site light theme ## 2026-05-28 — Authentication: align login/setup/modal styling with site light theme
### Changed ### Changed