Menu

#106 OOB password entry fails with misleading error on SSH/headless terminals

closed
nobody
None
2026-04-24
2026-04-09
Anonymous
No

Originally created by: kumaakh
Originally owned by: kumaakh

Summary

The out-of-band (OOB) password entry feature works correctly on GUI desktops, but produces a misleading \"❌ Password entry cancelled\" error when the user is on an SSH session or any headless environment where `$DISPLAY` / `$WAYLAND_DISPLAY` is unset — even though the underlying socket mechanism works fine in those environments.

Background

On Linux, launchAuthTerminal (src/services/auth-socket.ts:334-441) tries to open a GUI terminal emulator in order: gnome-terminal → xterm → x-terminal-emulator. The user types their password in that new window, and it is delivered over a Unix domain socket (UDS) at ~/.apra-fleet/auth.sock.

What Works Today

Environment Behavior
GUI desktop ($DISPLAY set) Auto-launches a terminal window ✅
SSH/headless, no terminal emulators installed Correctly falls back to a manual instruction ✅
Windows desktop Opens a new Command Prompt window ✅

What Is Broken

Environment Current behavior Expected behavior
SSH/Linux, terminal emulators installed but $DISPLAY unset which gnome-terminal succeeds → spawn attempted → exits immediately → misleading "❌ Password entry cancelled" Skip GUI attempt, show actionable instructions
SSH/Windows cmd.exe window spawned but appears on physical console, invisible to SSH user ❌ Detect no interactive desktop, show actionable instructions
Headless server (any OS), no display Same bug ❌ Same fix

UX Design: What Should Happen in SSH Sessions

The UDS at ~/.apra-fleet/auth.sock is a filesystem object on the server — any process on that machine can reach it. No GUI is needed. Two patterns work:

Option A — Second terminal (tmux/screen pane or second SSH session)

The system shows:

"No graphical display. In a second terminal on this machine, run:
apra-fleet auth <actual-member-name>
Then return here — the password will be received automatically."

Option B — ! operator in Claude CLI (preferred, eliminates second terminal)

Claude CLI's ! prefix runs OS commands in the current shell session. The system could instead instruct:

"Run this in your current session:
! apra-fleet auth <actual-member-name>"*

The password input is masked (noecho) so the LLM does not see the secret — only the success/failure result. This is cleaner than opening a second terminal.

Caveat: needs verification that Claude CLI's ! forwards stdin interactively (required for masked password input).

Key UX Requirements

  1. Substitute the actual member name — the message must show the real name (e.g. apra-fleet auth my-server), not a <name> placeholder. The system knows the member name at this point.
  2. apra-fleet must be in PATH — it is (same shell environment as Claude CLI), but worth verifying in edge-case install configurations.
  3. No misleading "cancelled" error — the current error implies user action caused the failure; the real cause is a missing display.

Proposed Code Fix

Add a display-presence check before attempting GUI terminal emulators:

// Linux
function hasGraphicalDisplay(): boolean {
  return !!(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
}

// Windows  
function hasInteractiveDesktop(): boolean {
  return process.env.SESSIONNAME === 'Console';
}

In launchAuthTerminal: if no graphical display is detected, skip the terminal emulator attempt and return a fallback with the actual member name substituted and ! apra-fleet auth <name> as the preferred action.

Affected File

src/services/auth-socket.tslaunchAuthTerminal function (~line 334–441)

Related

Tickets: #166

Discussion

  • Anonymous

    Anonymous - 2026-04-09

    Originally posted by: kumaakh

    Related: [#42] — the OOB terminal window on Windows also lacks paste support (Ctrl+V), Esc to cancel, and proper unblocking on window close. Both issues point to the same area of the OOB password entry UX needing a more robust cross-platform approach.

     

    Related

    Tickets: #42

  • Anonymous

    Anonymous - 2026-04-09

    Originally posted by: kumaakh

    Correction to issue body: Windows does not use a Unix Domain Socket. The two IPC mechanisms are:

    • Linux/macOS: UDS at ~/.apra-fleet/auth.sock (src/services/auth-socket.ts:10,35)
    • Windows: Named Pipe at \.\pipe\apra-fleet-auth-<username> (src/services/auth-socket.ts:33)

    The good news: Named Pipes on Windows are machine-scoped and accessible from any process on the server, including a second SSH session — same property as UDS on Linux. So the two-session pattern (or ! apra-fleet auth <name> in the same Claude CLI session) works on Windows SSH for the same reason.

    The root bug on Windows SSH remains the same: launchAuthTerminal spawns a cmd.exe /c start ... window (src/services/auth-socket.ts:418-419) which targets the physical desktop console, not the SSH session.

     
  • Anonymous

    Anonymous - 2026-04-09

    Originally posted by: kumaakh

    Correction on the ! operator suggestion: apra-fleet is not guaranteed to be in PATH on a remote SSH server. However, getAuthCommand() (src/services/auth-socket.ts:316-329) already resolves the correct invocation using process.execPath (SEA build) or process.argv[0] + absolute index.js path (dev mode) — so the fallback message already contains the exact full command the user needs to run.

    The ! operator idea still holds, but the instruction to the user should be:

    "Run this in your current session (copy exactly):
    ! <full-command-from-getAuthCommand> auth <member-name>"*

    Not a bare apra-fleet auth <name> — that would only work if apra-fleet happens to be in PATH.

     
  • Anonymous

    Anonymous - 2026-04-09

    Originally posted by: kumaakh

    ! operator approach confirmed not viable.

    Tested ! ~/.apra-fleet/bin/apra-fleet auth <name> from Claude CLI: the auth command uses an interactive masked password prompt that requires a real TTY. Claude CLI's ! operator provides no TTY, so the prompt receives empty input and immediately aborts with ✗ Empty password. Aborting.

    Passing the password as a CLI argument also doesn't work — it is ignored.

    Conclusions:

    • The second-terminal approach (another SSH session or tmux/screen pane) is the only viable option in headless/SSH environments
    • apra-fleet is installed at ~/.apra-fleet/bin/apra-fleet, not in system PATH — the fallback message must show the full path, not a bare apra-fleet auth <name>
    • getAuthCommand() already resolves to the full binary path via process.execPath, so the fallback message content is already correct — it just needs to be surfaced in SSH environments instead of the misleading "cancelled" error
     
  • Anonymous

    Anonymous - 2026-04-23

    Originally posted by: kumaakh

    Technical direction: Add a graphical-display presence check before attempting to spawn terminal emulators on Linux and Windows.

    In src/services/auth-socket.ts, add two helpers:

    • hasGraphicalDisplay(): returns true if process.env.DISPLAY or process.env.WAYLAND_DISPLAY is set (Linux)
    • hasInteractiveDesktop(): returns true if process.env.SESSIONNAME === 'Console' (Windows — 'Services' or undefined means headless)

    In launchAuthTerminal, on the Linux branch:

    • Check hasGraphicalDisplay() before calling findLinuxTerminal()
    • If no display: skip the terminal emulator attempt entirely, return a fallback string with the actual memberName substituted and ! apra-fleet auth <memberName> as the preferred action

    On the Windows branch:

    • Check hasInteractiveDesktop() before spawning cmd.exe /c start
    • If headless: return the same fallback

    The fallback message must substitute the real member name — no placeholder text. The memberName parameter is available at the call site.

    Key file: src/services/auth-socket.tslaunchAuthTerminal (~line 376) and findLinuxTerminal (~line 361). Small targeted fix, no schema changes.

     
  • Anonymous

    Anonymous - 2026-04-23
     
  • Anonymous

    Anonymous - 2026-04-24

    Ticket changed by: kumaakh

    • status: open --> closed
     

Log in to post a comment.

MongoDB Logo MongoDB