Skip to content

feat(auth): password login page for hosted deployments#101

Merged
aaronjmars merged 1 commit into
mainfrom
feat/hosted-login-page
Jul 10, 2026
Merged

feat(auth): password login page for hosted deployments#101
aaronjmars merged 1 commit into
mainfrom
feat/hosted-login-page

Conversation

@aaronjmars

Copy link
Copy Markdown
Collaborator

What

Replaces the optional browser Basic-Auth popup with a proper /login page for hosted (Docker/Railway) deployments, and makes the password gate mandatory there (fail-closed).

Requested follow-up to #100.

Behaviour

Scenario Result
Hosted + MINITOR_PASSWORD set, no session page → 307 /login?next=…, /api/*401
Valid session cookie served normally
Wrong-password / tampered / expired cookie /login
Hosted + no password 503 lock screen (never an open public instance)
/api/health always 200 (platform probes pass, even when locked)
Local ./minitor (not hosted, no password) fully open — unchanged

How

  • lib/auth/session.ts — HMAC-SHA256 signed, 30-day expiring session token via Web Crypto (same module runs in the Edge proxy and Node actions). HMAC key is MINITOR_PASSWORD, so rotating the password invalidates every session. sanitizeNext() blocks open redirects.
  • app/login/ — server page, client form (useActionState), and login/logout server actions setting an HttpOnly / SameSite=Lax / Secure cookie.
  • proxy.ts — migrates middleware.ts to the Next 16 proxy convention and gates on the session cookie.
  • settings-dialog.tsx — "Log out" button on hosted instances.
  • Docs (README, docker-compose.yml) note the password is required in hosted mode.

Verify

  • next build clean (TypeScript passes), no more middleware-deprecation warning.
  • 280 vitest tests pass (271 prior + 9 new session tests).
  • Driven live against the real standalone server (node .next/standalone/server.js) for every row in the table above.

Replace the optional browser Basic-Auth popup with a proper /login page for
hosted (Docker/Railway) deployments, and make the gate mandatory there.

- lib/auth/session.ts: HMAC-SHA256 signed, 30-day expiring session token via
  Web Crypto so the same module runs in the Edge proxy and Node actions. The
  HMAC key is MINITOR_PASSWORD, so rotating the password invalidates every
  session. sanitizeNext() blocks open redirects from the ?next= param.
- app/login: server page (redirects away if already authed / no password),
  client form (useActionState), and login/logout server actions that set and
  clear an HttpOnly, SameSite=Lax, Secure session cookie.
- proxy.ts: migrate middleware.ts to the Next 16 proxy convention and gate on
  the session cookie — pages redirect to /login?next=…, /api/* returns 401,
  /login and static assets pass through. Fail closed: MINITOR_HOSTED with no
  password serves a 503 lock screen; /api/health stays open for probes.
- settings-dialog: add a "Log out" button on hosted instances.
- test/session.test.ts: 9 tests for sign/verify/expiry/tamper/open-redirect.
- README + docker-compose: document that MINITOR_PASSWORD is required in
  hosted mode.
@aaronjmars aaronjmars merged commit 913e027 into main Jul 10, 2026
2 checks passed
@aaronjmars aaronjmars deleted the feat/hosted-login-page branch July 10, 2026 18:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant