Manage your passwords on macOS using pass, the standard Unix password manager

macos unix security shell

November 30, 2020

While there are tons of great password managers available on every platform, I was looking for something that would blend flawlessly in my environment without having to deal with any heavy GUI. Pass, the standard Unix password manager, does just that.
pass allows us to securely store all our credentials on our local machine as gpg files and access them effortlessly, whether it be from the command line or via additionnal plugins available for most modern browsers. In this tutorial we'll be focusing on using it in comination with BrowserPass on macOS. Note that plugins are available for mobiles devices as well (iOS and Android) that I haven't tested yet.
To make pass and browserpass work on macOS and Brave (actuallly any browser supporting the extension) I had to search through multiple sources and put it all together as I could not find any proper guide. With this article I hope to make the installation straightforward for anyone.
Note: I'm using Big Sur 11.0.1.
Installing pass and gnupg
Download pass with homebrew using the following command:
$ brew install pass
brew will also install gnupg among other dependencies.
Having done that we need to create a key using gpg. The key id will allow us to generate a password store. If you want to know more about gpg and encryption protocols available you can read about it but for now we'll juste use the default options. Run the following command to init the key creation process:
$ gpg --full-generate-key
Press enter to select the default options
gpg (GnuPG) 2.2.25; Copyright (C) 2020 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Please select what kind of key you want: (1) RSA and RSA (default) (2) DSA and Elgamal (3) DSA (sign only) (4) RSA (sign only) (14) Existing key from card Your selection? RSA keys may be between 1024 and 4096 bits long. What keysize do you want? (3072) Requested keysize is 3072 bits Please specify how long the key should be valid. 0 = key does not expire <n> = key expires in n days <n>w = key expires in n weeks <n>m = key expires in n months <n>y = key expires in n years Key is valid for? (0) Key does not expire at all Is this correct? (y/N) y
Enter a username (at least 5 characters long) and an email address. Then select a strong passphrase and make sure to remember it!
GnuPG needs to construct a user ID to identify your key. Real name: guimauve Email address: email@address Comment: You selected this USER-ID: "guimauve email@address" Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy. We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy. gpg: key 081B21D198B79A91 marked as ultimately trusted gpg: revocation certificate stored as '/Users/guimauve/.gnupg/openpgp-revocs.d/3329FEA2628BA8FB21705B17081B21D198B79A91.rev' public and secret key created and signed. pub rsa3072 2020-11-30 [SC] 3329FEA2628BA8FB21705B17081B21D198B79A91 uid guimauve <email@address> sub rsa3072 2020-11-30 [E]
To list our current active keys we use the following command:
$ gpg --list-secret-keys
We are interested in the key id that will allows us to to generate a password store. Enter the following command to display the key id:
$ gpg --list-secret-keys --keyid-format LONG
And copy your key id in the clipboard:
/Users/guimauve/.gnupg/pubring.kbx ---------------------------------- sec rsa3072/YOURKEYID 2020-11-29 [SC] ######################################### uid [ultimate] guimauve <email@address> ssb rsa3072/################ 2020-11-29 [E]
Initializing a password store
With our gpg key id copied in the clipboard, run the following command to init a password store. It will be created in your home folder.
$ pass init YOURKEYID
Having our password store initialized we can now add some credentials. But let's put pass aside for a moment and install browserpass first. We'll come back to the password store after having properly configured browserpass.
Most of the login processes usually happen in the browser. Browserpass will allow the browser to communicate with gpg and retreive passwords from there in exchange of our passphrase. Browserpass is actually made of 2 components:
  • A native application that will be installled via brew. It will allow the browser extension to communicate with gpg to fetch our credentials.
  • The browser extension, installed from your favorite browser webstore (in our case chrome's webstore) that will fill login forms for us.
Installing browserpass native messaging host
To make browserpass browser extension able to communicate with gpg we need to install browserpass host application. It is not yet available via homebrew's official repo but fortunately Amar1729 made it available through its own tap. Add Amar1729's repo and install browserpass:
$ brew tap amar1729/formulae $ brew install browserpass
Run the following command to generate a host file for your desired browser. I'm using Brave so the command will be:
$ PREFIX='/usr/local/opt/browserpass' make hosts-brave-user -f /usr/local/opt/browserpass/lib/browserpass/Makefile
Installing browserpass browser extension
Go the Chrome's webstore extension page and install it. That's all there is to it.
Configuring gnupg
To make browserpass able to communicate with gpg we need to modify gpg-agent.conf. In my case I didn't even have this file in the first place so I had to create it. You might have to do the same. It is located in ~/.gnupg.
1 # Enables gpg to find gpg-agent (deprecated since version 2.1) 2 # use-standard-socket 3 4 # Connects gpg-agent to the macOS keychain via pinentry-mac from GPGtools. 5 # This allows to trigger pinentry-mac GUI to enter our passphrase when needed 6 # and gpg key's passphrase to be stored in the login keychain, enabling automatic key signing. 7 pinentry-program /usr/local/bin/pinentry-mac
Reload gpg-agent using the following command. It should restart automatically.
$ gpgconf --kill gpg-agent
From now on browserpass should be ready to automatically fill our login forms if we ask it to, assuming we have some credentials to match these forms. Let's go back to pass and add some user/password combinations in our password store and see what happens.
Using browserpass and pass
To make our credentials parsable for browserpass we need to store them using one of the following conventions:
  • You can choose to give your .gpg file the username you are using for a given website and store your password in the file.
  • Or you can give your .gpg file a generic name (such as personal/work or whatever) and store both your username and password inside it.
I went with the latter since I find it to be clearer. Assuming you want to store existing passwords, use the following command to create a new record for a given website:
$ pass insert --multiline some_website/personal
browserpass github's page mentions that we can use different formats to make the credentials parsable. I like to go with the following:
1 user: guimauve # Email or username 2 password: aStrongPassword
Hopefully not my actual password...
If you want to edit your .gpg file use the following command:
$ pass edit some_website/personal
Note that pass can generate a random password using /dev/urandom. Use the following command to create a new record with a randomly generated password:
$ pass generate some_website/personal
To respect browserpass format we need to edit it after having created a record using generate. (--multiline option cannot be used with generate).
Having some credentials in our password store we can now use try the browserpass extension. Fire up your browser (in my case Brave) and go to a website for which you have a record. We'll use reddit for illustration purposes. Your reddit record should look something like the following in pass. Using 'pass list':
$ pass list Password Store ├── some_website └── personal ├── └── guimauve
Go to your favorite website (in our case reddit) and try to sign in. Using Command ⌘ + Shift + L, browserpass should display a record for the corresponding website. Press Enter to trigger pinentry-mac and enter your passphrase. If the passphrase is correct browserpass will automatically fill the form:
Final words
pass and browserpass have been working great so far. I could not think about something that would blend in my environment better than the combination of these two. Granted, the installation is not "super easy", but using it every day is. So in my opinion it's worth taking some time to set everything up and enjoy its simplicity on a daily basis.
Note that pass comes with auto completion support for bash, zsh and fish. If you are using zsh you might need to remove .zcompdump files and restart your shell to make it work.
$ rm ~/.zcompdump* $ exec zsh
Hope this article was helpful!