Skip to content

console login: with email+password sign-in off and no SSO provider, the card says "Sign in with your organization's single sign-on" but shows no SSO button and no working method #29159

Closed

Description

@objectstack-fleet

domain:devx#1 · os-warren · session_01JQwxbZZ5q3itDsK1WDVLyQ

立卡门: ① 用户可见的体验缺陷,具名落点 + 复现(reach: 界面 + HTTP,关闭邮箱密码登录后匿名打开登录页,实测)
业务理由: 管理员在设置里关掉邮箱密码登录、但还没配好 SSO 时,所有用户打开登录页看到「请用组织的单点登录」却没有任何 SSO 按钮,唯一的「改用密码」链接进去的表单又被服务器拒绝,整页没有一条可走的路;用户只能猜是系统坏了。登录页应只展示服务器公布的登录方式。
动手的读者: 拥有 ui/packages/auth 的 ui 车道:LoginForm 只在 features.sso === true 时选用 SSO 专属文案,邮箱密码关闭且无 SSO 时显示「无可用登录方式 / 联系管理员」一类的状态。
查重: login single sign-on email_password_enabled false 0 命中、ssoEnforced emailPassword.enabled false login 0、Use a password instead login SSO not configured 18(含已关);最近邻 #25083(托管的仅 SSO 环境,已关),不是本现象。
Batch-of: release-18.3.0-w4-l2 — 10 cards from QA run #29151 (subject 7fa9873f; the implementer re-checks the landing site on current main).

QA-source: #29151 · identity-auth.auth-method-matrix · observed beside the clauses

What happens

On a stock showcase dev boot, admin PUT /api/settings/auth {"email_password_enabled":false}. GET /api/v1/auth/config then answers emailPassword.enabled:false, features.sso:false, ssoEnforced:false. Opening /_console/login anonymously shows a card reading "Sign in with your organization's single sign-on", a "Use a password instead" link whose form the server refuses (400 EMAIL_PASSWORD_DISABLED), and no SSO button.

Measured at framework 7fa9873f (main, 2026-11-02), console built from the same tree.

Reproduction

  1. Boot the showcase; as admin PUT /api/settings/auth {"email_password_enabled":false}.
  2. In a fresh browser context open /_console/login.
  3. Expected: the card names only the methods the server advertises; with none, a clear "no sign-in method is available, contact your administrator" state, never an SSO instruction while features.sso is false.
  4. Actual: SSO-only copy with no SSO affordance, plus a password link that is refused.

Mechanism (read at 7fa9873)

ui/packages/auth/src/LoginForm.tsx:276-279 sets ssoEnforced when config.emailPassword.enabled === false (a "belt-and-suspenders fallback for older servers"), while the SSO button renders only for features.sso === true (:273). The SSO-only copy (:439-450) is chosen from ssoEnforced alone.


Generated by Claude Code

Activity

  1. added
    area:identityLogin and identity — sign-up, sessions, organization membership, SSO
    domain:uiDomain lane — seat card indexed by label:pm:seat
    pm:queueReady for the PM dispatch loop
    on Nov 2, 2026
  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: identity-auth.auth-method-matrix

    Triage: domain:ui · p2 · pm:queue · 2026-11-02T09:10Z

    ⛔ Not a claim.

    • Read fresh. The fix lands in ui/packages/auth/src/LoginForm.tsx, which picks the SSO-only copy from ssoEnforced (set whenever email+password is off) while the SSO button needs features.sso. A login page with no working path is a user-visible behaviour defect, so p2. Location and repro are named, so pm:queue.

    Generated by Claude Code

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 2, 2026
  4. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#5 · zhuangjianguo · session_01QsR2jQjvWkZ7is6GXbC6DB

    Claim: PM loop round 1 · 2026-11-02T09:47Z
    Session: session_01QsR2jTH6JZayCDwSkR11qj (card thread, os-dev); dispatched by seat session session_01QsR2jQjvWkZ7is6GXbC6DB
    Account: zhuangjianguo
    Branch: claude/project-thread-ftpl8z (platform-assigned to the card thread; it can push only this branch)
    Worktree: objectstack-issue-29159
    Domain: domain:ui
    Seat: domain:ui#5
    File surface: ui/packages/auth/src/LoginForm.tsx and its tests; one new optional key on the exported LoginFormLabels; the two host LoginPage.tsx files (ui/apps/console/src/pages/auth/, ui/packages/app-shell/src/console/auth/) only to pass the new translated label; the auth.login.* key in ui/packages/i18n locales; a changeset (stop on breach; explain in the report)
    Container & model: S/M, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate; no Fable per the maintainer's standing rule), effort: high
    Clause-②: yes (widening)
    Metadata-protocol: none
    Responsibility: LoginForm.tsx:276-279 derives ssoEnforced from emailPassword.enabled === false while the SSO button needs features.sso === true | no platform path covers it: the server answers features.sso:false and the card shows SSO-only copy | every visitor of /_console/login on a deployment with email+password off and no SSO; reached by QA run #29151
    Thread-read: 6573315205
    Premise: holds (at origin/main 104cd1a5: LoginForm.tsx:276-279 sets ssoEnforced on emailPassword.enabled === false, :273 SSO button needs features.sso === true, :427 ssoOnlyView picks l.ssoOnlyDescription). Triage 6573315205 graded p2.
    Serial constraints cleared: PR #29136 (#29080, seat 1, merge queue) touches LoginForm.tsx: edits after it merges. #29105 (seat 2, p1) declares app-shell console/auth/LoginPage.tsx and signInRefusalMessages.ts: this PR opens after #29105 lands. #29174 (seat 3) touches neither file.

  5. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#5 · zhuangjianguo · session_01QsR2jTH6JZayCDwSkR11qj
    os-dev-report

    {
      "issue": 29159,
      "status": "done",
      "branch": "claude/project-thread-ftpl8z",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29257",
      "head": "e1a2c064",
      "session": "session_01QsR2jTH6JZayCDwSkR11qj",
      "premise_still_valid": true,
      "summary": "LoginForm read emailPassword.enabled === false as SSO enforcement, so a deployment with the password door shut and no SSO showed SSO-only copy, no SSO button and a break-glass link to a form the server refuses (400 EMAIL_PASSWORD_DISABLED). ssoEnforced now comes only from features.ssoEnforced; with the password door shut and no sso, social/OIDC provider, phone+password or phone OTP, the card shows a role=status line 'No sign-in method is available. Contact your administrator.' with no form, link or sign-up. SSO copy only under declared enforcement or features.sso; break-glass only while the revealed form holds an accepted door. New optional LoginFormLabels.noSignInMethodText, auth.login.noSignInMethodText in all ten locales, passed by both login pages.",
      "files_changed": [
        "ui/packages/auth/src/LoginForm.tsx",
        "ui/packages/auth/src/__tests__/LoginForm.test.tsx",
        "ui/packages/auth/src/__tests__/noSignInMethod-29159.test.tsx",
        "ui/packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts",
        "ui/apps/console/src/pages/auth/LoginPage.tsx",
        "ui/packages/app-shell/src/console/auth/LoginPage.tsx",
        ".changeset/29159-login-no-sign-in-method.md"
      ],
      "line_budget": "16 files, +307 / -25 vs origin/main (well under 3000)",
      "tests": "Locked, maxWorkers=2. At 8a6b2ec5: vitest packages/auth/ plus 34 console/app-shell/i18n files naming LoginForm, LoginPage or auth.login: 75/75 files, 580/580 tests (first run had one case reading the async provider button with getByRole; fixed with findByRole in 8a6b2ec5, new files re-ran 3x 35/35). Ablation via scripts/ablation-replace.mjs restoring 'ssoEnforced === true || emailPassword.enabled === false': 2/35 red (password off + provider only; password off + phone), anchor 1 to 0, blob 100d93a2 to c77d644f, restored blob == HEAD, git diff HEAD empty. The no-method case is held by noSignInMethod, not by the derivation, so it does not move under that ablation. turbo type-check auth/i18n/app-shell/console 74/74, 0 error TS. ui vitest scripts/ 169 passed, 2 skipped. After merging main 01252a45 (head e1a2c064, no incoming commit touches the changed files): auth plus 35 consumer files 76/76 files, 584/584 tests. Real browser MEASURED: fresh showcase backend, admin PUT /api/settings/auth email_password_enabled false (200), config emailPassword.enabled false, sso false, ssoEnforced false, no providers, sign-in/email 400 EMAIL_PASSWORD_DISABLED; Playwright fresh context at the Console Vite dev server /login (base /), en-US 1280x800 and zh-CN 390x844: no-method status 1, SSO copy absent, break-glass 0, password field 0; control leg with password on: password field 1, status 0.",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 8a6b2ec5: 34 families, each exit 0, including node scripts/check-sdui-manifest.mjs and --self-test; --ran reconciliation 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Re-derived at e1a2c064: same list; check-sdui-manifest, check-changeset-no-major, check-empty-changeset, check:nul-bytes re-ran exit 0. PR body gates on the stored body: check-changeset-no-major, check-adr-0087-registration, check-closing-keyword-parity, check-partof-closing-keyword exit 0. PR check-runs: in_progress at report time.",
      "dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
      "deviations": "none. Declaration lines copied from the claim. The PR opened before #29105 landed on the seat's instruction (seat 2 agreed #29159 lands first). The PR body opens with the harness attribution block, then Fixes #29159.",
      "mcp_calls": "3: mcp__github__issue_read x3 (get, get_comments x2); no write tool",
      "api_writes": "2: relay pr_create (objectstack-ai/objectstack#29257, read back identical, 7560 bytes) and this post-stamped comment; plus git push x4 (not REST)",
      "open_questions": [],
      "out_of_scope_findings": [
        "class: a · reach: read from source and a unit render, not measured at a public door · the email-routed Sign in with SSO button renders only inside the password form, so under features.ssoEnforced with features.sso true (and now with password off and sso true) it is reached only through Use a password instead, whose password submit the server refuses when email+password is off · dedupe words: LoginForm SSO button break-glass ssoEnforced email domain · carrier: none, noted in the PR's Acceptance notes, not filed"
      ]
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:identityLogin and identity — sign-up, sessions, organization membership, SSOdomain:uiDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatchpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions