I have been managing passwords with pass, the standard UNIX password manager, for a while now, and I cannot recommend it enough. This particular password manager excels in its simplicity: one password is stored in one file, encrypted by GnuPG, inside of a Git repository. Categories of passwords are elegantly represented by the directory structure of the password store. pass has a simple command line interface, which allows for easy interfacing with other software, such as dmenu or rofi, through shell scripting.

Synchronization across different devices can be be achieved by a simple git push or a git pull. This way you will not have to trust a company like LastPass to synchronize your passwords for you - especially if you host your own Git server! You will be able to access and manage your passwords on any device, as there are great clients available for many different platforms.

Let’s get started.

Installation

pass is available in the standard repositories of most Linux distributions. Installing should be as simple as:

  • Debian/Ubuntu: apt install pass
  • Fedora: yum install pass
  • OpenSUSE: zypper in password-store
  • Gentoo: emerge -av pass
  • Arch: pacman -S pass

Setup

GnuPG

To encrypt and decrypt your passwords, pass uses GnuPG (GPG for short). You will need a GPG keypair before creating your password store. If you do not have one yet, run:

gpg --full-generate-key

This will create a new GPG keypair in ~/.gnupg, by default. Make sure to enter a strong password when prompted; this is the master password that will be needed to decrypt the passwords in your password store. To view your new public GPG key, run:

gpg --list-keys

The output will look something like this:

/home/test/.gnupg/pubring.kbx
-----------------------------
pub   rsa4096 2022-11-05 [SC]
      BC7F6D5FD6DD8DEC1F108221D8C7A6C84D1E6029
uid           [ultimate] Test User <test@testuser.com>
sub   rsa4096 2022-11-05 [E]

Creating the password store

We are now ready to create a new password store! Run the command below. Substitute <your-gpg-id> with your GPG ID; this is the long alphanumeric string in the output of gpg --list-keys (in my case, it is: BC7F6D5FD6DD8DEC1F108221D8C7A6C84D1E6029).

pass init <your-gpg-id>

That’s it! You have now set up your password store. A directory has been created in your home directory: ~/.password-store. This is where all your encrypted passwords will be stored.

Managing passwords

Let’s add some existing passwords to the password store. pass supports directories, which lets you organize passwords into (nested) categories. Below, we add a password for our Google account in the root of our password store, and one for GitLab in the ‘work’ folder.

pass insert google
pass insert work/gitlab

You will be prompted to enter and confirm the passwords. You can then list the passwords in your password store by running:

pass 

The output will look like this:

Password Store
├── google
└── work
    └── gitlab

To retrieve the password, use one of the following:

pass google 	# Output to terminal; or
pass -c google	# Copy to your clipboard

This will decrypt the file ~/.password-store/google.gpg, containing your password, and output it to your terminal or copy it to your clipboard if you pass the -c flag. Decrypting requires the password to your GPG key, which you will be prompted for.

Instead of continuing to use your old passwords (which you might re-use in several places), it is better to use randomly generated passwords for every account! To generate a new random password for my-account, use the pass generate:

pass generate my-account	# Generate password with 25 characters
pass generate -n my-account	# Do not use symbols in the password
pass generate my-account 15	# Generate a password with 15 characters

You can also update existing passwords this way; if the password already exists, you will be asked for confirmation to overwrite the existing password. Don’t worry, since pass uses Git, and every change to the password store is marked by a new commit, you can always revert back to previous versions of your passwords.

Of course, you can also manually edit passwords:

pass edit my-account

… and rename passwords:

pass mv my-account my-renamed-account

… and much more! For a full list of commands and options, simply type:

pass help

or check the man-page:

man pass

Pass and dmenu

pass comes installed with a handy script, passmenu, that allows you to query your passwords through dmenu, a powerful menu application. To select a password in dmenu and copy it to your clipboard, run:

passmenu

passmenu can also type the password out for you. Binding the command below to a key combination is very powerful: simply click wherever you need to enter your password, hit the key combination, select the password you need, and passmenu will fill it in for you. This is much more powerful than using, for example, a browser plugin, as this approach works in any application; not just the browser!

passmenu --type

One-time passwords

One-time passwords (OTP) are commonly used for multi-factor authentication. They are mostly used through mobile apps, such as Google Authenticator or Microsoft Authenticator. A six-digit code is typically retrieved through such an app, which has to be entered as a second step during authentication.

You will be glad to learn that pass also supports OTP through the pass-otp extension. You will likely find it in the standard repositories of your Linux distribution.

Most websites that support OTP will show you a QR code that would normally have to be scanned by a smartphone app. Instead, download the image to your computer. I will assume you saved it to qr.png. You will need to install zbar, which should also be available in the standard repositories of your Linux distro, to decode the QR code.

Use the following command to decode the QR code, which contains the OTP secret, and append it to the password file of my-account:

zbarimg -q --raw qr.png | pass otp append my-account

You can also scan the QR code using your webcam:

zbarcam -q --raw | pass otp append my-account

If you now run pass my-account, you will see that an additional line has been added with the OTP secret, starting with otpauth://totp/.

Now, to retrieve an OTP token, simply run:

pass otp my-account

And you will see a six-digit OTP code being printed to your terminal. Pretty cool, right?

Unfortunately, no passmenu-otp script is packaged with pass-otp to use it in combination with dmenu, but it is very simple to create one yourself. Simply copy the passmenu script to a location in your $PATH, for example:

cp "$(which passmenu)" ~/.local/bin/passmenu-otp

Edit the script such that pass otp is called instead of just pass. The bottom five lines should now look like this:

if [[ $typeit -eq 0 ]]; then
	pass otp show -c "$password" 2>/dev/null
else
	pass otp show "$password" | { IFS= read -r pass; printf %s "$pass"; } | $xdotool
fi

Once that’s done, just bind passmenu-otp to a key combination of your choice, and using one-time passwords will have just become a whole lot easier!

Unlock your GPG keyring at login

Decrypting the passwords in your password store requires you to enter the password of your GPG key every time, if you do not perform any further configuration. This can become annoying if you have to enter many passwords per day. A solution is to use gpg-agent (a key management daemon for GPG) and set the cache timeout to a high value. This would, however, still require you to enter the password at least once after logging in to your system. There is a useful project called pam-gnupg that automatically starts gpg-agent upon login and passes on your login password to it, in order to unlock your GPG key automatically. This, of course, does require you to have the same password for your GPG key and your Linux user.

If you run an Arch-based distro, you can install pam-gnupg trough the AUR. Otherwise, manual installation is also quite painless:

git clone 'https://github.com/cruegge/pam-gnupg'
cd pam-gnupg
./autogen.sh
./configure
make
sudo make install

Once installed, you need to edit the PAM configuration of your display manager. PAM is a framework for user authentication within Linux. I currently use lightdm, so in my case, I had to edit /etc/pam.d/lightdm, and add the following lines at the end:

auth     optional  pam_gnupg.so store-only
session  optional  pam_gnupg.so

To let gpg-agent accept the password passed on by pam-gnupg, add the following line to ~/.gnupg/gpg-agent.conf:

allow-preset-passphrase

You probably also want to set the cache timeout to a large value, so that you will not be bothered with password prompts anyway, after the initial cached password times out. Add the following line to the same file to set the timeout to 86400 seconds, i.e., 24 hours:

max-cache-ttl 86400

Finally, you need to let pam-gnupg know which key to unlock. First, run:

gpg --list-secret-keys --with-keygrip

This will give you output similar to this:

/home/test/.gnupg/pubring.kbx
-----------------------------
sec   rsa4096 2022-11-05 [SC]
      BC7F6D5FD6DD8DEC1F108221D8C7A6C84D1E6029
      Keygrip = CC63EC89672E3F8FDD0F2A24323BE34BA0D7317D
uid           [ultimate] Test User <test@testuser.com>
ssb   rsa4096 2022-11-05 [E]
      Keygrip = 3A4D0CF6F136972948B8370956002C4EA7EBF9BF

Copy the keygrip marked with [E], in my case 3A4D0CF6F136972948B8370956002C4EA7EBF9BF, and write it to ~/.pam-gnupg:

echo '3A4D0CF6F136972948B8370956002C4EA7EBF9BF' > ~/.pam-gnupg

Now log out and back into your system, and your GPG key should be automatically unlocked, freeing you from password prompts!

Clients on different platforms

There are several nice clients for pass on different platforms. To start with, there is a Qt-based cross-platform GUI front-end for called QtPass, which works on Linux, BSD, macOS and Windows. It is a full-fledged client, and a great option for those who do not care for the command line or dmenu-style interface.

The client I have most experience with (apart from passmenu) is the Android app called Password Store. You can synchronize your Git repository through HTTPS or SSH, and it supports Autofill and one-time passwords, among many other features. And all of that is packaged in a clean-looking user interface. You can find it on F-Droid. Highly recommended!

It looks like there is a similar open-source app for iPad and iPhone called Pass. I have no experience with this one, but it looks good and is well reviewed.

I occasionally use Windows for my day job, so I needed a client here as well. There is QtPass, but I was looking for a dmenu-like experience that I have gotten so used to on Linux. If you are like me, you will definitely like pass-winmenu. It offers a simple pop-up menu that reminds me of rofi, which can be brought up by pressing a configurable key combination.