auth: park login flow — circle back

Auth work is parked until after ship. While AUTH_ENABLED=false:
  - login.html now auto-redirects to / on load (no one should ever see
    the login screen while auth is off; it was confusing).
  - sidebar power button is hidden entirely when /auth/me returns a
    synthetic user, so there's no broken-feeling no-op control.
  - Removed connect-pg-simple createTableIfMissing flag in case
    v9.0.1's handling of that option was responsible for the recent
    boot 502 (the schema is created by migration 021 anyway).

The /auth/login + session.regenerate() + cookie fix from c34a721
stays in place — when we re-enable auth it'll work end-to-end. The
sessions table from migration 021 stays. Operator action to restore
auth later: set AUTH_ENABLED=true + SESSION_SECRET=<random> in the
mam-api environment and restart.
This commit is contained in:
opencode 2026-05-27 03:04:32 +00:00 committed by ZGaetano
parent 34bf1c7b7f
commit d1f9557dd1
3 changed files with 17 additions and 24 deletions

View file

@ -78,9 +78,6 @@ app.use(
pool,
tableName: 'sessions',
pruneSessionInterval: 3600,
// Belt-and-braces: connect-pg-simple will CREATE TABLE on its first
// write if migration 021 somehow didn't run. Cheap, idempotent.
createTableIfMissing: true,
}),
secret: SESSION_SECRET,
resave: false,

View file

@ -264,23 +264,22 @@
$('show-setup').onclick = e => { e.preventDefault(); clearFlash(); showSetup(); };
$('show-login').onclick = e => { e.preventDefault(); clearFlash(); showLogin(); };
// First-run detection: if no users exist, skip the sign-in panel entirely
// and present the create-admin form. This is the only state in which the
// app is unusable without intervention, so we want the operator routed
// there automatically rather than relying on them to click the small link.
// Auth is parked for now. If the server reports auth is disabled, bounce
// straight to the app — no one should ever land on this screen while
// AUTH_ENABLED=false. If the server is unreachable, leave the panel
// visible so the operator at least sees something.
(async () => {
try {
const r = await fetch(API + '/setup-status', { credentials: 'same-origin' });
if (r.ok) {
const d = await r.json();
if (!d.auth_enabled) {
location.replace('/');
return;
}
if (d.needs_setup) {
showSetup();
showFlash('No accounts yet — create the first admin to continue.', 'info');
} else if (!d.auth_enabled) {
// Auth is off server-side; logging in does nothing. Tell the
// operator clearly instead of letting them fill out the form
// and watch the redirect loop back to /login.html.
showFlash('Authentication is disabled on the server (AUTH_ENABLED=false). Set AUTH_ENABLED=true in mam-api and restart.', 'error');
}
}
} catch (_) { /* offline → leave the login panel visible */ }

View file

@ -177,18 +177,15 @@ function Sidebar({ active, onNavigate, me, collapsed, onToggle }) {
{me?.role || '—'}{me?.synthetic ? ' · auth off' : ''}
</div>
</div>
<button className="icon-btn" aria-label="Sign out" data-tip="Sign out" title="Sign out"
onClick={async () => {
// Best-effort logout works whether auth is on or off. With
// AUTH_ENABLED=true the server clears the session; with auth
// off there's no session, so we still bounce to /login.html
// so the operator can see "auth disabled" messaging and choose
// to enable it instead of staring at a no-op power button.
try { await window.ZAMPP_API.fetch('/auth/logout', { method: 'POST' }); } catch (_) {}
window.location.replace('/login.html');
}}>
<Icon name="power" />
</button>
{me?.synthetic ? null : (
<button className="icon-btn" aria-label="Sign out" data-tip="Sign out" title="Sign out"
onClick={async () => {
try { await window.ZAMPP_API.fetch('/auth/logout', { method: 'POST' }); } catch (_) {}
window.location.replace('/login.html');
}}>
<Icon name="power" />
</button>
)}
</div>
</aside>
);