Every Mac ships with the same OpenSSH toolchain that powers a large share of the internet's server infrastructure. That means you do not need to install anything to create a modern, hardware-grade authentication setup. You open Terminal, run one command, and you have a cryptographic identity that can log you into a VPS, push commits to a Git host, deploy to a cloud provider, or tunnel into a database behind a firewall.
The appeal is simple: passwords can be guessed, phished, reused, or leaked from a database breach. A key pair cannot be guessed in any practical sense. The private half never leaves your machine, and the public half is safe to paste anywhere. When a server challenges you, your Mac proves possession of the private key without ever transmitting it. An attacker who compromises the server's stored public keys gains nothing useful.
That asymmetry is why most hosting providers, code forges, and cloud platforms now push key-based access as the default and often disable password logins entirely. If you have ever been locked out of a fresh server because password authentication was switched off, the fix was almost always to upload a public key first.
Mac users get a few extra conveniences on top of the standard stack. The system Keychain can remember passphrases, the ssh-agent launches automatically in most shells, and GUI clients integrate with the same ~/.ssh directory that Terminal uses. So whether you prefer typing commands or clicking through a polished app, everything stays in sync.
This guide walks through the full lifecycle: generating keys, choosing the right algorithm, protecting the private key with a passphrase, wiring up config files, and fixing the errors that trip people up most often. It also covers how to turn the whole process into a repeatable walkthrough you can hand to teammates.
Before running commands, it helps to understand the handshake, because almost every confusing error message maps back to one of these steps.
When you generate a key pair, the tool produces two mathematically linked files:
id_ed25519) stays on your Mac. It is the secret. Anyone who copies it can impersonate you.id_ed25519.pub) is a short text string you can share freely. It gets appended to a file called authorized_keys on each server you want to reach.During login the server sends a random challenge. Your SSH client signs it with the private key, and the server verifies the signature using the public key it already has. No secret crosses the wire.
On a typical Linux server, your public key lives in ~/.ssh/authorized_keys inside your user account. One line per key, one key per line. If your key is not in that file, or the file has permissions the SSH daemon considers unsafe, authentication fails even though your local setup is perfect.
The very first time you connect, your client shows a fingerprint prompt and asks whether to trust the host. Saying yes writes an entry to ~/.ssh/known_hosts. From then on, a changed host key triggers a loud warning, because it can indicate a man-in-the-middle attempt or a rebuilt server.
Running an SSH agent means you unlock your private key once per session instead of typing the passphrase on every connection. On macOS the agent and the Keychain can be linked, so the passphrase survives reboots and logins without you thinking about it.
Once these four pieces make sense — private file, public file, server-side list, agent cache — troubleshooting becomes a matter of asking which one is misconfigured.
Open Terminal with Spotlight (Command + Space, then type Terminal) or find it under Applications > Utilities. Then run:
ssh-keygen -t ed25519 -C "you@example.com"
The -t flag selects the algorithm, and -C attaches a comment that helps you identify the key later. The comment is not secret; using your email or a device name is a common convention because hosting dashboards display it in lists of authorized keys.
The tool asks three things:
~/.ssh/id_ed25519, or type a custom path such as ~/.ssh/id_ed25519_work_laptop. Custom names are the single best habit for keeping separate identities for work, personal projects, and client systems.You will see output like a random art block and a confirmation that the key was saved. Two files now exist:
ls -la ~/.ssh
To view the public key, use:
cat ~/.ssh/id_ed25519.pub
That single line is what you paste into a Git host, a cloud console, or a server's authorized_keys. Never paste the file without the .pub extension. A quick sanity check: the private key starts with -----BEGIN OPENSSH PRIVATE KEY----- and should never leave your machine, not even to a password manager you do not fully control.
If the server still accepts password login and you have ssh-copy-id available:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server.example.com
Otherwise, paste the public key line manually into ~/.ssh/authorized_keys on the remote host using whatever access you currently have.
A written runbook plus a short screen recording covers nearly every onboarding case. When you capture the walkthrough, keep the Terminal font large, narrate why each flag exists rather than only what to type, and hide or blur any fingerprint or key material that appears on screen. If you produce the recording with an AI-assisted video tool, favor a consistent visual style and add captions for the exact commands, because viewers will pause the video to copy them.
Not all key types are equal, and the choice you make now determines how much friction you feel later.
ssh-keygen -t rsa -b 4096 -C "you@example.com".Decision rule: start with Ed25519, and only fall back to RSA 4096 when a connection fails with an algorithm negotiation error.
After a year of work you will have several keys. Names like id_ed25519, id_ed25519_github_personal, id_ed25519_work_gitlab, and id_ed25519_prod_bastion tell you instantly which key belongs where. Vague names guarantee accidental reuse of a privileged key on a low-trust service.
Reuse is tempting, but a key shared between a hobby project and production infrastructure means a leak in the hobby project compromises production. Creating a new pair takes seconds; recovering from an incident takes days.
If your Mac has a Secure Enclave and you use a FIDO2 security key, you can store a key on hardware so the private material cannot be exported at all. This is the strongest option available and worth considering for administrative access to critical systems, even if the setup takes a few extra minutes.
A passphrase turns a stolen private key file into an expensive problem instead of an instant breach. The catch is that typing it constantly is annoying, and annoyance leads people to remove it. macOS solves this cleanly.
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
The --apple-use-keychain flag stores the passphrase in the system Keychain so the agent can unlock the key automatically after a reboot. On older system versions the equivalent flag was -K; if one form is rejected, try the other.
Add this to ~/.ssh/config so the behavior applies automatically:
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_ed25519
With that in place, the first connection after login prompts once and subsequent ones do not.
ssh-keygen -p -f ~/.ssh/id_ed25519
This rewrites the passphrase on the existing key. The public key and its entries on every server stay valid, so there is no re-deployment work. Rotating a passphrase every six to twelve months is a reasonable routine for administrator keys.
Automation keys used by CI runners or deployment scripts cannot prompt for input, so they usually have no passphrase. Compensate by giving those keys the narrowest possible server-side access, restricting them with command options in authorized_keys, and storing them only in the CI provider's encrypted secret store.
Command line is not mandatory. Several mature apps manage the same files, which means you can switch between clicking and typing without breaking anything.
~/.ssh/config lets you replace long connection strings with short aliases:
Host prod-web
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519_prod
IdentitiesOnly yes
Now ssh prod-web does everything. The IdentitiesOnly yes line is especially valuable: without it, the client offers every key the agent holds, and servers that limit authentication attempts may reject you before reaching the right key.
~/.ssh/config directly, so remote development inherits your aliases.Review ~/.ssh a few times a year. Delete keys for hosts you no longer use, confirm that each key file has 600 permissions, and check that known_hosts does not contain stale entries for recycled IP addresses. Ten minutes of cleanup prevents confusing failures later.
Generate keys, then protect them. The following checklist covers the mistakes that cause most real incidents.
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/config
OpenSSH refuses to use a private key that other users could read. If you ever see a permissions warning, fix it with the commands above rather than random experimentation.
Replace keys every six to twelve months for privileged access, and immediately when a laptop is lost, sold, or repaired by a third party. Revocation means removing the public key line from authorized_keys on every host where it was installed; keeping a short inventory of where each key lives makes that possible in minutes.
Forwarding your agent lets a remote host use your local keys. If that host is compromised, so is every system your agent can reach. Prefer ProxyJump in your config to hop through a bastion without exposing the agent.
Host internal-db
HostName 10.0.4.20
User analyst
ProxyJump bastion
The authorized_keys file accepts options before the key itself, which lets you limit damage from a leaked automation key:
from="203.0.113.0/24",command="/usr/local/bin/backup.sh" ssh-ed25519 AAAA... backup-runner
This key can only run one command from one network range, regardless of who holds it.
On a server, list what currently has access:
awk '{print $1, $NF}' ~/.ssh/authorized_keys
Removing unknown lines is one of the fastest security improvements available on an inherited system.
Most failures fall into a handful of categories. Working through them in order saves time.
This is the catch-all message, and it almost always means one of four things: the public key is not in the server's authorized_keys, the server user is different from the one you assumed, the client offered the wrong key, or permissions on the server side are too open. Diagnose with:
ssh -v user@server.example.com
The verbose output prints each key the client offers and the server's response. If your key never appears in that list, the client is not finding it, which points back to naming and config issues.
If SSH complains that your key is too open, run the chmod commands from the hardening section. On macOS the group staff often has read access by default on files copied from other locations.
System updates occasionally reset the Keychain state, so the agent loses cached passphrases. Re-add the key with ssh-add --apple-use-keychain and confirm that UseKeychain yes is present in your config.
This appears when the agent offers many keys and the server allows only a few attempts. Fix it by setting IdentitiesOnly yes for the host and pointing IdentityFile at exactly one key.
You rebuilt a server, recycled an IP, or connected through a proxy that presents a different host key. Remove just that entry:
ssh-keygen -R server.example.com
Then reconnect and verify the new fingerprint with a trusted source before accepting it.
There is no recovery path for a forgotten passphrase. Generate a new pair, install the new public key on every host, verify access, then delete the old private key and its server entries.
Check the syntax, since indentation and typos matter, and confirm file permissions are not so open that the client refuses to read it. Also make sure you are editing the file for the user account actually running the command. A config saved in an administrator account does not apply when you sudo into another user.
Hangs usually indicate a network path problem rather than an authentication problem. Test with ssh -v to see how far the handshake progresses, check whether a VPN is required, and confirm the host is reachable with nc -vz server.example.com 22.
Open Terminal and run ssh-keygen -t ed25519 -C "you@example.com", then press Return to accept the default path and enter a passphrase twice. The public key appears in ~/.ssh/id_ed25519.pub and is ready to paste into any service.
The default directory is ~/.ssh inside your home folder. That path is hidden in Finder, but you can reach it with Command + Shift + G and typing ~/.ssh, or by revealing hidden files.
Choose Ed25519 unless a specific system rejects it. Fall back to RSA at 4096 bits only for older hardware, appliances, or internal tools that have not added modern algorithm support.
On a laptop that leaves your home, no. Without a passphrase, the private key file is the only protection, and copying that file grants full access. For automation running on a controlled runner, an empty passphrase is a common and acceptable trade-off when the key is scoped narrowly.
One per trust boundary. A separate key for personal Git hosting, work Git hosting, production servers, and disposable test machines keeps a single compromise from cascading across everything you can reach.
Use ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host when password login is still enabled. Otherwise paste the single line from the .pub file into ~/.ssh/authorized_keys on the remote machine.
The agent is not persisting the unlock. Add the key with ssh-add --apple-use-keychain ~/.ssh/id_ed25519 and include AddKeysToAgent yes plus UseKeychain yes in ~/.ssh/config. After a system update you may need to re-add it once.
Technically yes, but it is poor hygiene. Git hosting services often display keys by comment, and a key used broadly is harder to revoke cleanly. Separate keys make audits straightforward and removals surgical.
Every six to twelve months for privileged access, and immediately after any device loss, repair, resale, or suspected compromise. Rotation is only useful if you also remove the old key from every server that trusted it, which is why keeping an inventory matters.
List the contents of authorized_keys, review the comment at the end of each line, match entries against your team's inventory, and remove anything you cannot attribute. Then confirm you can still log in with your own key before closing the session.
No. Terminal covers every operation, including generation, passphrase changes, agent management, and removal. GUI clients are a convenience layer over the same files, which is why switching between them never requires re-creating keys.
Write a short runbook with the exact commands, then record a two- to four-minute screen capture showing a real key generation and first login. Keep the recording focused on one task, blur anything sensitive, and caption the commands so viewers can copy them accurately. Combining a written checklist with a short walkthrough video is usually faster for onboarding than either format alone.
Generating an SSH key on a Mac takes seconds, but the value comes from the surrounding habits: distinct keys per trust boundary, passphrases protected by the Keychain-backed agent, a tidy ~/.ssh/config that prevents identity confusion, and periodic review of what each server trusts. Start with a single Ed25519 pair, add it to the agent, install the public half where you need access, and keep a short note about where it lives. From there, expand into hardware-backed options and authorized_keys restrictions as your responsibilities grow. Done consistently, the workflow disappears into the background, and you stop thinking about authentication entirely until the day something breaks.

Alexander
Vidu Q4 alternatives compared: Kling 4.0, Seedance 2.5, Wan 3.0, and Runway Gen-4 — 4K support, input modes, durations, audio, and what each costs in credits on Domer.
The top 4K AI image generators on Domer compared: Flux 3 Klein, Nano Banana 2.1, GPT Image 2.5, GPT Image 2, and Nano Banana Pro — 4K credit costs, reference limits, and speed.
Nano Banana 2.1 vs GPT Image 2.5 Flare compared: credit costs per resolution, aspect ratios, reference images, text rendering, and which tasks fit each model.