Key authentication
Key authentication replaces passwords with a cryptographic proof: the private key never leaves your machine; the server holds only the public key and verifies a signed challenge. ssh-agent caches the decrypted key so you type the passphrase once per session.
Password authentication for SSH has a fundamental weakness: the password travels across the network (encrypted, yes, but still a shared secret that can be brute-forced, leaked, or phished). Key authentication eliminates that weakness entirely. The private key never leaves your machine — not even a hash of it. Instead, the server sends a random challenge, your client signs it with the private key, and the server verifies the signature using only the public key it already has. A stolen public key is useless without the private key to match it. This is the model every serious deployment uses.
By the end of this lesson you will know how to generate an Ed25519 keypair, distribute the public key to a server, understand what ~/.ssh/authorized_keys does, and use ssh-agent so you only unlock your key once per session.
After this lesson you can generate an Ed25519 keypair with ssh-keygen -t ed25519, copy the public key to a server with ssh-copy-id, explain why the private key must never leave the client, start ssh-agent and add a key with ssh-add, and understand the caution required around agent forwarding.
Generate a keypair with ssh-keygen -t ed25519. Ed25519 is the current best practice: small keys (256-bit), fast, and no weak parameter choices unlike RSA.
ssh-keygen -t ed25519 -C "deploy key for server.example"Output:
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/alice/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/alice/.ssh/id_ed25519
Your public key has been saved in /home/alice/.ssh/id_ed25519.pubThis creates two files:
~/.ssh/id_ed25519— the private key. Treat this like a password.600permissions, never shared, never uploaded anywhere.~/.ssh/id_ed25519.pub— the public key. Safe to copy everywhere. This is what you put on servers.
The -C comment is embedded in the public key and helps you identify the key later. The passphrase encrypts the private key on disk; without it, a stolen key file is immediately usable.
The private key never leaves the client — this is the security guarantee. During authentication:
- The server sends a random challenge (a nonce).
- Your SSH client signs the challenge with your private key.
- The signature is sent to the server.
- The server verifies the signature using the public key stored in
~/.ssh/authorized_keys.
The server never sees the private key. A network attacker who intercepts the session only sees the signature — useless without the private key that produced it. This is fundamentally different from passwords, where the actual secret must be transmitted.
~/.ssh/authorized_keys on the server authorises specific public keys. Each line is one public key. When you connect, SSH matches your public key against the list. Format:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFakePublicKeyDataHereForIllustration deploy@workstation.exampleThe file permissions must be correct: ~/.ssh/ directory must be 700, and authorized_keys must be 600. SSHd rejects auth from authorized_keys if the permissions are too open — this prevents other users on the server from injecting their own keys.
ssh-copy-id is the safe, automated way to add your public key:
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@server.exampleIt appends your public key to ~/.ssh/authorized_keys on the remote host (creating the file and directory if needed, with correct permissions). After this runs, you can SSH with your key instead of a password.
To add a key manually (when ssh-copy-id is unavailable):
cat ~/.ssh/id_ed25519.pub | ssh deploy@server.example \
'mkdir -p ~/.ssh && chmod 700 ~/.ssh && \
cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'ssh-agent caches the decrypted private key in memory so you enter the passphrase once. Without the agent, every SSH connection prompts for the passphrase. With it:
eval "$(ssh-agent -s)" # start agent, export SSH_AUTH_SOCK
ssh-add ~/.ssh/id_ed25519 # add key; prompts for passphrase once
ssh deploy@server.example # no passphrase prompt — agent signs the challengeThe agent runs as a background process. The SSH_AUTH_SOCK environment variable points to a Unix domain socket; the SSH client uses this socket to ask the agent to sign challenges on its behalf. The private key never leaves the agent process — the client only receives the signature.
To see what keys are loaded:
ssh-add -lTo remove all keys from the agent (for example before stepping away):
ssh-add -DAgent forwarding (-A) lets remote hosts use your local agent — but carries risk. If you SSH to a bastion and then SSH from the bastion to an internal server, normally the bastion would need its own key for the internal server. With agent forwarding, the internal server’s SSH challenge is forwarded back through the bastion to your local agent:
ssh -A deploy@bastion.example # enable forwarding for this sessionThe risk: the root user on bastion.example can access your agent socket and impersonate you to any other server your agent can reach. Agent forwarding should only be enabled on bastion hosts you fully trust and control. For most multi-hop setups, ProxyJump in ~/.ssh/config (covered in the previous lesson) is safer because the hop is handled locally, with no agent exposure on the intermediate host.
Set up passwordless access to a new server from scratch.
# 1. Generate a key if you don't have one
ssh-keygen -t ed25519 -C "laptop key $(date +%Y-%m)" -f ~/.ssh/id_ed25519
# 2. Copy the public key to the server (uses password auth once)
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@server.example
# 3. Verify key auth works
ssh deploy@server.example 'echo "key auth works"'
# 4. Optionally disable password auth on the server (in /etc/ssh/sshd_config):
# PasswordAuthentication no
# Then: systemctl reload sshdAfter step 4, password auth is impossible even if an attacker guesses the password — only holders of an authorised private key can connect. This is the standard hardening step for any internet-facing SSH server.
▸Why this works
On macOS, ssh-add --apple-use-keychain ~/.ssh/id_ed25519 stores the passphrase in the macOS Keychain so it persists across reboots. The ~/.ssh/config entry AddKeysToAgent yes and UseKeychain yes make this automatic on every login. On Linux there is no built-in keychain integration; the common pattern is to start ssh-agent in ~/.bashrc or ~/.profile and add keys at login, or use a desktop keyring (GNOME Keyring, KDE Wallet) that integrates with SSH.
▸Common mistake
Never generate a key without a passphrase on a shared or persistent machine. A key without a passphrase is immediately usable by anyone who can read the file — including other users on a multi-user system, or an attacker who gains read access to your home directory. The passphrase encrypts the private key on disk; ssh-agent then caches the decrypted form in memory, so you get the convenience of not typing the passphrase on every connection without sacrificing the protection. No passphrase = no protection at rest.
During SSH key authentication, what does the server use to verify your identity?
Key authentication works via challenge-response: the server sends a nonce, the client signs it with the private key (which never leaves the client), and the server verifies the signature against the public key in ~/.ssh/authorized_keys. ssh-keygen -t ed25519 generates the pair; ssh-copy-id safely distributes the public key to a server. ssh-agent holds the decrypted private key in memory so you type the passphrase once per session. Agent forwarding (-A) is a footgun: it exposes your agent socket on the remote host — use ProxyJump instead wherever possible.
Practice
Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.
Something unclear?
Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.