diff --git a/README.md b/README.md index 1f4af880..55738d64 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,9 @@ The app runs as an authenticated Express/Postgres service with a browser fronten ### Admin And Security -- Local auth, role-based access, TOTP 2FA, OIDC/SSO, email verification, and optional Turnstile. +- Sign in with a password or a six-digit code emailed to you — offered side by side, because a code depends on mail arriving and a password does not. +- Role-based access, TOTP 2FA, OIDC/SSO, email verification, and optional Turnstile. Passwords are argon2id, with bcrypt rows rehashed on their next sign-in. +- Registration can be open, closed, or invite-only with generated codes. A code can be revoked while live, and deleted only once it is spent. - Admin panel for users, settings, prompts, models, logs, and Learning Hub content. - Audit, API, access, and client-error logs with redaction hardening. - OpenBao secret loading support at container startup. @@ -59,7 +61,7 @@ The app runs as an authenticated Express/Postgres service with a browser fronten Browser Whisper has been removed from the runtime. The app should not ship browser Whisper workers, browser-local Whisper model downloads, Transformers.js browser STT, or Browser Whisper setup docs. -Speech-to-text is handled server-side through configured providers such as Google/Gemini, AWS Transcribe, LiteLLM, or OpenAI Whisper. Browser-native Web Speech remains gated behind an explicit user setting when present in the browser. +Speech-to-text is handled server-side through configured providers such as Google/Gemini, AWS Transcribe, LiteLLM, or OpenAI Whisper. Browser-native Web Speech remains gated behind an explicit user setting when present in the browser — it is off unless a user turns it on, because Chrome and Edge send that audio to Google. ## Quick Start diff --git a/docs/authentication.md b/docs/authentication.md index c03262b3..631029ad 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -158,6 +158,10 @@ would make low digits slightly likelier. `loginCodes.sweep()` clears codes more than a day past expiry. It is fire and forget: housekeeping never fails a request. +Verified end to end against the running server with SMTP configured: a code is +requested from the sign-in screen, the mail is sent, and typing the code returns +200 from `/login-code/verify` and enters the app. + ### Frontend note `public/js/authFetch.js` keeps an allowlist of `/api` paths callable with no