Traversio

Keyboard-Interactive Authentication

Generic challenge-response authentication through async callbacks.

Public Method

Traversio exposes generic keyboard-interactive authentication through:

.keyboardInteractive(
    submethods: [String],
    responseProvider: @Sendable (SSHKeyboardInteractiveChallenge) async throws -> [String]
)

submethods is the optional hint list sent in the initial keyboard-interactive request. For the common case, pass [].

End-to-End Example

import Traversio

@available(macOS 26.0, iOS 26.0, *)
func connectWithKeyboardInteractive(password: String) async throws {
    let configuration = SSHClientConfiguration(
        host: "example.com",
        username: "deploy",
        authentication: .keyboardInteractive(
            submethods: [],
            responseProvider: { challenge in
                if challenge.prompts.count == 1,
                   challenge.prompts[0].prompt.localizedCaseInsensitiveContains("password") {
                    return [password]
                }

                throw CancellationError()
            }
        ),
        hostKeyPolicy: .knownHostsFile("/Users/me/.ssh/known_hosts")
    )

    try await SSHClient.withConnection(configuration: configuration) { connection in
        let result = try await connection.execute("whoami")
        print(String(decoding: result.standardOutput, as: UTF8.self))
    }
}

Challenge Model

SSHKeyboardInteractiveChallenge includes:

  • username
  • serviceName
  • name
  • instruction
  • languageTag
  • prompts

Each SSHKeyboardInteractivePrompt contains:

  • prompt
  • shouldEcho

Traversio supports multiple challenge rounds, including zero-prompt informational messages, and preserves prompt order when sending responses back to the server.

Important Rules

  • your callback must return exactly one response per prompt
  • if the response count does not match, Traversio throws SSHAuthenticationMethodError.invalidKeyboardInteractiveResponseCount(expected:received:)
  • if the server sends a zero-prompt informational message, your callback should return []
  • UI integration, secure secret storage, and higher-level password heuristics remain application responsibilities

Limits

Supported behavior:

  • generic challenge-response auth
  • multi-round exchanges
  • zero-prompt informational messages

Remaining gaps:

  • live OpenSSH validation specifically for this public path
  • helper adapters for system UI or secure secret stores
  • broader host-key verification and the rest of the auth hardening matrix around this public path

On this page