← All posts

SFTP two-factor authentication: keyboard-interactive explained

SFTP two-factor authentication almost always works through an SSH mechanism called keyboard-interactive. The server sends one or more prompts, such as "Verification code:", and the client shows them to you and sends back your answers. Combined with a required public key, that gives you a genuine second factor: something you have (the key) and a time-based code from your phone. This post explains how keyboard-interactive works, how to set up OpenSSH to require a key and a code, and what to configure in an SFTP client.

How keyboard-interactive works

SSH supports several authentication methods. The familiar ones are password and publickey. Keyboard-interactive, defined in RFC 4256, is a generic question-and-answer exchange: the server sends a set of prompts, each marked as to whether the answer should be echoed on screen, and the client replies with the answers. The server can go round as many times as it likes.

Because the prompts are arbitrary text, the server can ask for anything. On Linux, OpenSSH hands keyboard-interactive to PAM, so whatever PAM modules are configured decide the questions. Add a TOTP module and one of the prompts becomes a six-digit code. TOTP itself is specified in RFC 6238: the code is derived from a shared secret and the current time, and changes every 30 seconds.

Requiring two methods with AuthenticationMethods

By default, any single successful method logs you in. OpenSSH's AuthenticationMethods directive changes that by listing methods that must all succeed, in order. To require a key and then a code:

AuthenticationMethods publickey,keyboard-interactive

The client offers its key first. The server accepts it as a partial success and says which methods can continue, and the client then completes keyboard-interactive. You can watch this by connecting with verbose output, ssh -v deploy@example.com, and reading the debug lines:

debug1: Authentications that can continue: publickey
debug1: Offering public key: /Users/you/.ssh/id_ed25519 ED25519 ...
debug1: Authentications that can continue: keyboard-interactive

The second "can continue" line, listing only keyboard-interactive, is the server saying the key was accepted and a code is still needed. The sshd_config manual page documents the directive in full.

Setting up key plus TOTP on Ubuntu or Debian

This is the common setup using the Google Authenticator PAM module, which works with any TOTP app. Keep a second SSH session open while you do it, so a mistake can't lock you out.

  1. Install the module:
    sudo apt install libpam-google-authenticator
  2. As the user who will log in, run google-authenticator, answer yes to time-based tokens, and scan the QR code with your authenticator app. Save the emergency scratch codes somewhere safe. It also asks whether to disallow reuse of the same code; saying yes is more secure, and it matters for clients that open several connections, as explained below.
  3. Add the module to /etc/pam.d/sshd:
    auth required pam_google_authenticator.so
    For key plus code without a password as well, comment out the @include common-auth line in the same file. Otherwise PAM asks for the account password too.
  4. In /etc/ssh/sshd_config (or a file in /etc/ssh/sshd_config.d/), set:
    KbdInteractiveAuthentication yes
    UsePAM yes
    AuthenticationMethods publickey,keyboard-interactive
    Older OpenSSH releases call the first directive ChallengeResponseAuthentication.
  5. Test the configuration, then restart:
    sudo sshd -t && sudo systemctl restart ssh

Open a fresh connection from another terminal before closing the old one. You should be asked for a verification code after the key is accepted. If you need to roll this out gradually, adding nullok to the PAM line lets users who haven't set up a code yet log in without one; remove it once everyone is enrolled.

SFTP uses the same SSH authentication, so the same rules apply to sftp sessions and to chrooted SFTP-only users.

Password plus code instead of a key

If you keep @include common-auth and set AuthenticationMethods keyboard-interactive, PAM asks two questions over keyboard-interactive: the account password, then the code. It's still two factors, but a password is weaker than a key and can be phished along with the code. Prefer a key where you can.

Configuring two-factor SFTP in Wharf

Wharf supports both shapes. In the site editor, the authentication Method picker offers:

When the server sends a prompt, Wharf shows its text exactly as the server wrote it, with the site's name as the heading, and hides what you type when the server asks for no echo. If the server asks two questions, you'll see two prompts in turn. Codes are answered at connect time and never saved.

A few practical points:

For the key part of the setup, the SSH key guide covers generating and importing a key on a Mac, and the support page explains why Wharf imports keys into the Keychain rather than reading ~/.ssh. The protocols Wharf supports are listed on the features page.

Troubleshooting