Home / Alt manpages / age-keygen(1)

  • age-keygen(1)
  • User command
  • linux

Generate and Verify an age Identity with age-keygen

age-keygen makes you a fresh identity file and its matching public recipient in one shot. This walkthrough then proves the two actually belong together before you trust either of them. The examples use age-keygen 1.1.1 from Ubuntu package age 1.1.1-1ubuntu0.24.04.3+esm1.

Allow about ten minutes. You need a shell and the installed age package. No elevated privileges are normally required. The identity file holds a private key, so treat every command that reads or copies it as security-sensitive from here on.

1. Confirm the installed command

Check the executable and version before you trust any example against it. Read-only, nothing to undo:

$ command -v age-keygen
/usr/bin/age-keygen
$ age-keygen --version
1.1.1
$ dpkg-query -W -f='${Package} ${Version}\n' age
age 1.1.1-1ubuntu0.24.04.3+esm1

The installed 1.1.1 interface has -o, -y and --version. Upstream docs already describe a newer -pq option for post-quantum hybrid keys, but this release and its local manpage have never heard of it. Do not paste a newer example into this installation without checking its own help first.

Checkpoint

If your version is not 1.1.1, run age-keygen --help and compare the available options before continuing.

2. Generate the identity into a new file

Pick a path nothing else is using, then let age-keygen do the actual work:

$ install_dir="$HOME/.config/age"
$ mkdir -p "$install_dir"
$ umask 077
$ age-keygen -o "$install_dir/keys.txt"
Public key: age1<generated-recipient>

The public key is fine to hand to anyone who will encrypt data for you. The file itself holds the secret identity and must never be shared. age-keygen writes the identity to the file and prints the matching public key to standard error; the recipient is random every single run, so nobody else will ever generate yours.

The umask 077 line tightens permissions for anything this shell creates afterwards. The program also writes its output file with mode 0600 on the tested installation. Check the result without ever printing the secret:

$ stat -c '%a %n' "$HOME/.config/age/keys.txt"
600 /home/YOUR_USER/.config/age/keys.txt
$ sed -n '1,2p' "$HOME/.config/age/keys.txt"
# created: 2026-09-22T10:00:00+01:00
# public key: age1<generated-recipient>

The timestamp and public key are just comments. The third line is the secret key, so keep cat away from it in a terminal recording, a support ticket or a log. Back up the identity and you have also backed up the ability to decrypt everything addressed to its recipient, so guard that backup the same way.

3. Avoid an accidental overwrite

Safety boundary

age-keygen -o refuses to replace an existing path, which saves you when a script gets rerun by accident:

$ age-keygen -o "$HOME/.config/age/keys.txt"
age-keygen: error: failed to open output file "/home/YOUR_USER/.config/age/keys.txt": file exists

The exact path and wording can vary, but the command exits non-zero and the old file stays put. Do not "solve" this by deleting the identity before checking where it is used and making a secure backup. There is no age-keygen undo for a deleted key, full stop.

Genuinely need a second identity? Use a new filename such as keys-2026-09.txt and note which recipient belongs to which purpose. Do not rename or replace a key just because its public key is annoying to type.

4. Derive and verify the recipient

Use -y to read the identity and spit out its matching recipient with the comments stripped:

$ age-keygen -y "$HOME/.config/age/keys.txt"
age1<generated-recipient>

Compare that against the public key already in the file. A small shell check makes the verification explicit while keeping the secret line well out of the output:

$ expected=$(sed -n 's/^# public key: //p' "$HOME/.config/age/keys.txt")
$ actual=$(age-keygen -y "$HOME/.config/age/keys.txt")
$ test "$expected" = "$actual" && printf '%s\n' 'recipient matches identity'
recipient matches identity

That comparison checks the identity's own comment against the value calculated fresh from its secret key. If it fails, stop and inspect the file path and contents carefully. Never edit the secret line by hand. If the file is damaged, generate a separate identity and recover encrypted data from a known-good backup or the correct original key instead.

5. Use standard input when a file is not convenient

-y will happily read an identity from standard input when you give it no path. Useful in a controlled pipeline, but it drags shell history, process supervision and logs into your secret-handling review:

$ age-keygen -y < "$HOME/.config/age/keys.txt"
age1<generated-recipient>

Warning

Stick to the explicit filename for routine administration, it is far easier to audit. Never place the secret identity directly in a command argument, a URL, a shell variable exported to child processes, or an issue report.

6. Pass the recipient to age

The derived recipient is the only value anyone encrypting for you actually needs. Save just that public value as a recipients file:

$ age-keygen -y "$HOME/.config/age/keys.txt" > "$HOME/.config/age/recipients.txt"
$ stat -c '%a %n' "$HOME/.config/age/recipients.txt"
644 /home/YOUR_USER/.config/age/recipients.txt

A recipients file has no private key in it and can go to anyone or anything that encrypts for you. If it turns out wrong, regenerate it from the authoritative identity rather than hand-editing key material. The related age(1) command consumes it with --recipients-file; encryption and decryption are separate jobs from key generation entirely.

Done means

  • age-keygen --version was checked and the examples match the installed interface.
  • A new identity was written to a deliberate path with mode 0600.
  • The secret line was kept out of logs, tickets and shared shell output.
  • age-keygen -y produced the recipient expected by the identity file.
  • The recipient can be shared, while the identity file remains protected and backed up securely.
  • No existing identity was overwritten or deleted.