Description
When an SSH server requires multi-factor authentication with AuthenticationMethods publickey,password in sshd_config, Termix fails to complete the connection. The publickey step succeeds, but the subsequent password step fails because the ssh2 client sends keyboard-interactive instead of the password method.
Steps to Reproduce
- Configure sshd with:
AuthenticationMethods publickey,password
PasswordAuthentication yes
KbdInteractiveAuthentication no
- In Termix, create a credential with auth type
key, a private key, and a password
- Attempt to connect
Expected Behavior
After publickey succeeds (partial auth), ssh2 should send password as the next auth method, completing the connection.
Actual Behavior
After publickey succeeds, ssh2 sends keyboard-interactive (because tryKeyboard: true is hardcoded in the connect config). The server rejects it since KbdInteractiveAuthentication is disabled, and the connection fails. The client disconnects without ever trying the password method.
Server Logs
Partial publickey for user from x.x.x.x port 60474 ssh2: ED25519 SHA256:...
userauth_finish: failure partial=1 next methods="password"
userauth-request for user service ssh-connection method keyboard-interactive
authmethod_lookup: method keyboard-interactive not enabled
Received disconnect from x.x.x.x port 60474:11:
Root Cause
In dist/backend/backend/ssh/terminal.js, the connect config auth methods are mutually exclusive (else if branches):
authType === "password" → sets connectConfig.password
authType === "key" → sets connectConfig.privateKey
There is no code path that sets both privateKey and password on the ssh2 connect config. Additionally, tryKeyboard: true is always set, causing ssh2 to prefer keyboard-interactive over password.
Suggested Fix
When authType === "key" and a password is also available on the credential, set both connectConfig.privateKey and connectConfig.password, and set tryKeyboard: false to force ssh2 to use the password method instead of keyboard-interactive.
// In the "key" auth branch, after setting privateKey:
if (resolvedCredentials.password) {
connectConfig.password = resolvedCredentials.password;
connectConfig.tryKeyboard = false;
}
Alternatively, consider adding a new authType like "key+password" for explicit multi-factor support.
Environment
- Termix: latest (ghcr.io/lukegus/termix:latest)
- Server: OpenSSH 10.3, Arch Linux
- ssh2 (Node.js library) used by Termix backend
Description
When an SSH server requires multi-factor authentication with
AuthenticationMethods publickey,passwordinsshd_config, Termix fails to complete the connection. The publickey step succeeds, but the subsequent password step fails because the ssh2 client sendskeyboard-interactiveinstead of thepasswordmethod.Steps to Reproduce
key, a private key, and a passwordExpected Behavior
After publickey succeeds (partial auth), ssh2 should send
passwordas the next auth method, completing the connection.Actual Behavior
After publickey succeeds, ssh2 sends
keyboard-interactive(becausetryKeyboard: trueis hardcoded in the connect config). The server rejects it sinceKbdInteractiveAuthenticationis disabled, and the connection fails. The client disconnects without ever trying thepasswordmethod.Server Logs
Root Cause
In
dist/backend/backend/ssh/terminal.js, the connect config auth methods are mutually exclusive (else ifbranches):authType === "password"→ setsconnectConfig.passwordauthType === "key"→ setsconnectConfig.privateKeyThere is no code path that sets both
privateKeyandpasswordon the ssh2 connect config. Additionally,tryKeyboard: trueis always set, causing ssh2 to preferkeyboard-interactiveoverpassword.Suggested Fix
When
authType === "key"and a password is also available on the credential, set bothconnectConfig.privateKeyandconnectConfig.password, and settryKeyboard: falseto force ssh2 to use thepasswordmethod instead ofkeyboard-interactive.Alternatively, consider adding a new
authTypelike"key+password"for explicit multi-factor support.Environment