How-to

Making an SSH Key Work in a Graphical SFTP Client

7 min read

ssh deploy@example.com logs you straight in. You point your SFTP client at the same server, the same key, the same username — and it asks for a password, or fails outright.

This is one of the most common support questions for any graphical file transfer app on macOS, and it almost always comes down to one of five things. They are worth checking in this order, because the first two account for most cases and take seconds to rule out.

If you do not have a key yet, this is the wrong page — generating one, installing it with ssh-copy-id and hardening the server is covered step by step in setting up SSH keys on a Mac. Come back once ssh user@host works.

1. The app never got permission to read ~/.ssh

Start here. Any app distributed through the Mac App Store runs inside the App Sandbox, and a sandboxed app cannot read arbitrary paths on your disk. ~/.ssh is very much an arbitrary path — an app cannot quietly enumerate your private keys, which is the entire point of the mechanism.

The Terminal has no such restriction, which is exactly why the same key behaves differently in the two places. Nothing is broken; the app simply has not been handed the file yet.

The fix is to select the key through the app’s open panel, once. That act of choosing is what grants access — macOS remembers the consent for that specific file. In Upstream the key is then stored in your Keychain, so the panel does not come back on later connections.

This is also why importing ~/.ssh/config brings across the path in each IdentityFile line rather than the key itself. The path is a note about which file to ask you for; the authorisation still happens once, at the first connection.

2. You pointed it at the public key

The second most common cause, and an easy mistake to make because both files sit side by side with almost the same name:

~/.ssh/id_ed25519        ← private. This is the one the client needs.
~/.ssh/id_ed25519.pub    ← public. This one goes on the server.

A client given the .pub file cannot sign anything, so authentication fails and most servers fall back to asking for a password — which looks like “the key was ignored” rather than “the wrong file was supplied”. If the file you selected ends in .pub, that is your answer.

3. The key is in a format the client will not parse

Three formats turn up in practice, and they are not interchangeable:

  • OpenSSH — the modern default, starting -----BEGIN OPENSSH PRIVATE KEY-----. This is what ssh-keygen writes today and what clients handle best.
  • PEM / PKCS#1 — older, starting -----BEGIN RSA PRIVATE KEY-----. Still common in keys handed out by hosting panels and in .pem files from cloud providers.
  • PuTTY .ppk — a Windows format. No macOS client reads it directly.

Check which one you have:

head -1 ~/.ssh/id_ed25519

A .ppk has to be converted before anything on a Mac will use it — puttygen key.ppk -O private-openssh -o id_ed25519 if you have PuTTY’s tools installed, otherwise ask whoever issued it for an OpenSSH copy. For a legacy PEM key, ssh-keygen -p -f ~/.ssh/id_rsa -m RFC4716 rewrites it in place to the modern format without changing the key itself, so the server side keeps working untouched.

One more wrinkle: a key encrypted with an old cipher can be readable by OpenSSH and unreadable by a third-party library. If the format looks right and it still fails, re-encrypting it with ssh-keygen -p is a quick thing to try.

4. The key is fine — the server is refusing it

If the file is right and the app still cannot log in, the rejection may be happening on the far side. The usual causes:

Permissions on the server. SSH silently ignores ~/.ssh/authorized_keys if it, or its directory, is group- or world-writable. This is the single most common server-side cause:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

The wrong account. The key is installed for deploy, and the client is connecting as root or as your control-panel username. Keys are per-account, not per-server.

A key type the server has disabled. Hardened configurations sometimes refuse RSA with SHA-1 signatures, which strands older id_rsa keys. Generating an ed25519 key resolves it.

The fastest way to tell server-side from client-side: run ssh -v user@host and read the lines after Offering public key. If the server accepts it there, the problem is on your Mac; if it does not, no client will do better.

5. It only ever worked through the agent

This one is genuinely confusing, because the key appears to work in the Terminal and yet the file on disk is not what is authenticating you.

If your key was added to ssh-agent — by ssh-add, or automatically through UseKeychain yes in your ssh config — then ssh has been authenticating from the agent’s copy in memory. The file on disk might be missing, renamed, or encrypted with a passphrase you have long forgotten, and you would never notice.

Check what the agent is actually holding:

ssh-add -l

If that lists a key and the path you expect does not exist, the file is the problem, not the app. The related subject of forwarding an agent onward to another host is covered in SSH agent forwarding on a Mac.

Passphrases, and where they end up

A passphrase encrypts the private key on disk, so a stolen backup is not a stolen server. Keep it.

In a sandboxed client the passphrase is stored in the Keychain alongside the key reference, so you enter it once rather than at every connection. If the app asks repeatedly, it is usually because the Keychain item was never written — which loops back to cause 1, the file grant.

Step by step

  1. Confirm it works in the Terminalssh -i ~/.ssh/id_ed25519 user@host. If this fails, the problem is not the client and no setting in the app will fix it.
  2. Check you selected the private key, not the file ending in .pub.
  3. Check the format with head -1 on the key file, and convert a .ppk or an old PEM to OpenSSH if that is what you have.
  4. Grant the app access to the file once through its open panel — sandboxing means this consent is explicit and cannot be inferred.
  5. If it still fails, run ssh -v and read what happens after Offering public key to find out whether the rejection is local or server-side.
  6. Check the agent with ssh-add -l if the key seems to work everywhere except the app.

Questions people ask

Why can the Terminal read my key when the app cannot?

Because the Terminal is not sandboxed and an App Store app is. A sandboxed app has no standing permission to read ~/.ssh; you grant access to a specific file by selecting it, once. That restriction is a security property, not a defect.

Do I have to re-select the key every time?

No. The grant persists, and the key reference and passphrase are kept in the Keychain. Being asked repeatedly usually means the first grant did not complete.

Can I use my key for FTP or FTPS too?

No. SSH keys authenticate SSH, so they apply to SFTP only. FTPS authenticates the server with a certificate but still authenticates you with a password — see certificates and host keys.

The client says “invalid key format” but ssh accepts it. What now?

Almost always a PEM-era key or an old encryption cipher that OpenSSH still tolerates. ssh-keygen -p -f <keyfile> rewrites it in the modern OpenSSH format, leaving the public key — and therefore the server — unchanged.

Does a passphrase-protected key work in a GUI client?

Yes. You enter the passphrase once when the key is authorised, and it is stored in the Keychain from then on.

Can I use the same key for several servers?

Yes, and it is normal. Use a separate key per server only when you need to revoke access to one of them independently.

Upstream — the native FTP, FTPS & SFTP client for macOS

A transfer queue you can pause, resume and reorder, folder synchronization with a dry-run preview, live remote editing and credentials in the macOS Keychain. Free to download, no subscription.