Is there an existing issue for this?
Summary
Summary
When an instance has only email+password enabled (magic login off, no OAuth providers), the identifier-first flow — email screen → backend emailCheck → password screen — adds a roundtrip and a screen for a decision that has exactly one outcome. Render email + password on one screen in that case.
Current behavior
auth-root.tsx always starts at EAuthSteps.EMAIL, submits the email to the emailCheck endpoint (auth.service.ts), and only then routes to EAuthSteps.PASSWORD / UNIQUE_CODE and SIGN_IN / SIGN_UP. This branching exists to pick between password, magic-code, and OAuth. On an instance where password is the sole method there is nothing to branch on, yet users still pay:
- an extra network roundtrip and a second screen/click on every login;
- flaky password-manager autofill — the password field isn't in the DOM at page load, so Bitwarden/1Password can't do a standard single-shot fill (see the companion autocomplete-token issue);
- account enumeration: the
emailCheck response distinguishes existing vs non-existing users before any credential is supplied, which lets an unauthenticated caller enumerate valid accounts. A combined email+password screen that returns a single generic "invalid email or password" removes that oracle.
Proposed behavior
Keep identifier-first whenever more than one auth method is enabled (magic-code and/or OAuth) — that's where it earns its keep. When the instance config exposes password as the only method (is_email_password_enabled === true && is_magic_login_enabled === false and no OAuth providers), render a single classic login form: email (autocomplete="username") + password (autocomplete="current-password") together, submitting directly.
This is:
- backward compatible — multi-method instances are unchanged;
- config-driven — decided from the same instance config
auth-root.tsx already reads;
- a security improvement — no pre-credential existence oracle on single-method instances.
Why should this be worked on?
Rationale
Self-hosted single-tenant instances are the common case, and many run password-only. For them the identifier-first machinery is friction with no upside: worse UX, broken autofill, and a user-enumeration surface. Gating it on "more than one method enabled" preserves the flexibility where it matters and drops the cost where it doesn't.
References
Is there an existing issue for this?
Summary
Summary
When an instance has only email+password enabled (magic login off, no OAuth providers), the identifier-first flow — email screen → backend
emailCheck→ password screen — adds a roundtrip and a screen for a decision that has exactly one outcome. Render email + password on one screen in that case.Current behavior
auth-root.tsxalways starts atEAuthSteps.EMAIL, submits the email to theemailCheckendpoint (auth.service.ts), and only then routes toEAuthSteps.PASSWORD/UNIQUE_CODEandSIGN_IN/SIGN_UP. This branching exists to pick between password, magic-code, and OAuth. On an instance where password is the sole method there is nothing to branch on, yet users still pay:emailCheckresponse distinguishes existing vs non-existing users before any credential is supplied, which lets an unauthenticated caller enumerate valid accounts. A combined email+password screen that returns a single generic "invalid email or password" removes that oracle.Proposed behavior
Keep identifier-first whenever more than one auth method is enabled (magic-code and/or OAuth) — that's where it earns its keep. When the instance config exposes password as the only method (
is_email_password_enabled === true && is_magic_login_enabled === falseand no OAuth providers), render a single classic login form: email (autocomplete="username") + password (autocomplete="current-password") together, submitting directly.This is:
auth-root.tsxalready reads;Why should this be worked on?
Rationale
Self-hosted single-tenant instances are the common case, and many run password-only. For them the identifier-first machinery is friction with no upside: worse UX, broken autofill, and a user-enumeration surface. Gating it on "more than one method enabled" preserves the flexibility where it matters and drops the cost where it doesn't.
References
autocomplete="off"from [VPAT-27] chore(security): disable autocomplete on sensitive input fields #8517 breaks password managers / fails WCAG 1.3.5)