· · 8 min read Beginner

Pass: the Unix password manager that just works

Pass is a minimalist command-line password manager. Learn how to get started quickly and discover advanced features like git sync and browser integration.

A wooden drawer of sealed envelopes she opens with one string next to a cloud creature's subscription vault

TL;DR pass keeps each password as a GPG-encrypted file in a directory, and the directory is the whole data model. pass -c email/gmail puts a password in your clipboard from any terminal, pass git push backs the store up, and the fzf script further down is how I look up every password I have. The price is GPG key management, and it’s a real price.

I used KeePass for years. Then 1Password. Then Bitwarden. All decent tools, and every one of them was too much for what I asked of it. Too much UI, too many features, and a password always lived on the other side of an app I had to alt-tab into. A small interruption, and they added up.

Then I found pass. It stores passwords. That’s the feature list. I’ll walk you through it the way I learned it, from the one command that hooked me to the setup I run today.

Files in a directory, encrypted

Pass calls itself the “standard unix password manager.” Under the hood it’s a shell script of roughly 700 lines that stores each password as a GPG-encrypted file in a directory. No database. No proprietary format. No cloud sync bolted on. It’s small enough to read in an afternoon, and that matters to me. When something breaks, I want to be able to find out why.

~/.password-store/
├── email/
│   ├── gmail.gpg
│   └── protonmail.gpg
├── social/
│   └── github.gpg
└── work/
    ├── gitlab.gpg
    └── jira.gpg

Each .gpg file is an encrypted text file holding a password and, if you want, some extra lines. The directory tree is your organisation, and there’s nothing else to learn.

Working in five minutes

Install it

# macOS
brew install pass gnupg

# Debian/Ubuntu
sudo apt install pass gnupg

# Arch
sudo pacman -S pass gnupg

A GPG key

Pass encrypts with GPG, so you need a key. If you don’t have one yet:

gpg --full-generate-key

Choose RSA, 4096 bits, and fill in your name and email. Remember the passphrase. You’ll type it every time you decrypt a password, and nobody can recover it for you.

Initialize the store

# Use your GPG key ID or email
pass init "tom@example.com"

This creates ~/.password-store/ with a .gpg-id file that records which GPG key is in use.

Your first password

# Generate a new password
pass generate email/gmail 24

# Or add an existing password
pass insert social/github

That’s the whole setup. You have a working password manager.

Get it back out

# Show password in terminal
pass email/gmail

# Copy to clipboard (disappears after 45 sec)
pass -c email/gmail

This was the moment it clicked for me. No app to launch, no extension to wake up. One command and the password is in my clipboard.

Why it fits a terminal-first day

I live in a terminal, and pass never asks me to leave it. When I need a work password:

pass -c work/gitlab

Done. It sits in my clipboard for thirty seconds and then it’s gone.

Because the store is plain files in a directory, a few things come for free. It’s searchable, with pass find gitlab or plain ls ~/.password-store/. It’s scriptable, so pass show -c $(pass find jira | head -1) works. And it plugs into anything that can run a command: dmenu, rofi, fzf, Alfred, your own scripts.

A .gpg file can hold more than a password. The convention is that the first line is the password and everything after it is metadata.

pass edit email/gmail
SuperSecurePassword123!
---
username: tom@gmail.com
url: https://mail.google.com
otp: otpauth://totp/Gmail:tom@gmail.com?secret=JBSWY3DPEHPK3PXP
notes: recovery email is backup@proton.me

You can pull TOTP (2FA) codes straight out of it too:

# With pass-otp extension
pass otp email/gmail

Git sync, the part that sealed it

Pass has git built in, and this is why I stopped looking at other password managers.

# Initialize git repo
pass git init

# Every change is automatically committed
pass generate new/password 20
# → [master 1a2b3c4] Add generated password for new/password.

# Push to remote
pass git push

Your password store is now a git repository. That gives you automatic backups to your remote, sync between machines with a plain pass git pull, a version history of every password, and merge conflicts when you change the same one on two machines. I’ll get back to that last one.

Mine lives in a private repo on my own Forgejo. A fresh machine is one clone:

git clone git@forgejo.example.com:tom/password-store.git ~/.password-store

Every password, back. No vendor in the middle of that pull.

Browser integration

“But I want auto-fill in my browser.”

You can have it. There are extensions for Firefox and Chrome:

Browserpass reads your store, matches the URL against your directory names, and fills the form. It works better than I expected.

~/.password-store/
├── github.com/
│   └── tom.gpg      # auto-matched on github.com
├── gitlab.com/
│   └── work.gpg
└── mail.google.com/
    └── personal.gpg

Fuzzy finding with fzf

This is what I use every day. A small script:

#!/bin/bash
# passfzf - fuzzy find and copy password

password=$(find ~/.password-store -name "*.gpg" | \
  sed 's|.*/\.password-store/||; s|\.gpg$||' | \
  fzf --height 40% --reverse)

[[ -n "$password" ]] && pass -c "$password"

Bind it to a hotkey and you have fuzzy lookup in one keystroke. If you live in rofi instead, rofi-pass does the same job:

rofi-pass

Teams and extensions

Multi-key encryption

Sharing passwords with a team? Pass takes more than one GPG key:

pass init key1@example.com key2@example.com

Now both keys can decrypt everything. You can also scope keys per directory:

# Only you have access to personal/
echo "your-key-id" > ~/.password-store/personal/.gpg-id

# The whole team has access to shared/
echo -e "key1\nkey2\nkey3" > ~/.password-store/shared/.gpg-id

pass init

Three extensions I use

Pass has an extension system. pass-otp adds TOTP and HOTP:

# Add OTP
pass otp insert email/gmail
# Paste the otpauth:// URL

# Generate code
pass otp email/gmail
# → 482193

pass-tomb wraps the whole store in a Tomb container, for the case where someone has physical access to your machine:

pass tomb open
# do your thing
pass tomb close

pass-update rotates passwords in bulk:

pass update -l 32 work/*

The downside is GPG

Pass is simple because it leans on GPG, and GPG key management is anything but. That’s the bill for a password store that’s yours, and I’d rather hand it to you now than have you find it later.

Lose the key, lose everything

Lose your GPG private key and every password goes with it. Permanently. No “forgot password” link, no support desk to dig you out.

So back up the key in more than one place. Remember the passphrase, and writing it on paper in a safe is a reasonable move. And consider a hardware key like a YubiKey. I do all three, and my setup is at the bottom.

GPG will fight you

GPG is powerful and famously unfriendly. You’ll meet errors like these:

gpg: decryption failed: No secret key
gpg: problem with the agent: No pinentry
gpg: public key not found

If you haven’t used GPG before, the learning curve is steep. Pinentry popups that refuse to appear, agents that hang, keys that go missing. I’ve lost evenings to it, and I’m telling you up front.

No official mobile app

There’s no official pass app. Third-party ones exist. On Android, Password Store works well and syncs via git. On iOS, Pass for iOS does git sync too. Neither is as polished as 1Password or Bitwarden on a phone. You configure git credentials and import your GPG key first, and that takes time.

“Share this password with a colleague” is not a feature. Multi-key encryption works, but every person on the team needs a GPG key. For a quick share with someone non-technical, pass is the wrong tool.

Merge conflicts in encrypted files

Git sync is great until you change the same password on two machines and get a merge conflict in a file git can’t read. Resolving that is no fun. It rarely happens if you run pass git pull before you change anything, but it can.

When pass is the right call

You’re comfortable in the terminal. You already use GPG, or you’re willing to learn it. You want your data under your own control, with no cloud unless you pick one. You want to wire passwords into scripts. And you want something small enough to audit, roughly 700 lines of bash. If that’s you, pass fits.

When to choose something else

You share passwords with family or colleagues who don’t have GPG. You want a polished phone app with zero setup. You’d rather not deal with GPG key management at all. Or your organisation mandates a password manager for compliance. Then Bitwarden or 1Password, and no shame in it.

My setup

What I run today:

# ~/.zshrc
export PASSWORD_STORE_DIR="$HOME/.password-store"
export PASSWORD_STORE_CLIP_TIME=30

# Fuzzy find alias
alias p='passfzf'

# Quick copy
alias pc='pass -c'

The store lives in a private repo on my own Forgejo, synced between laptop, desktop and phone with git. The GPG key sits on a YubiKey, with a backup on an air-gapped machine.

Is it more setup than Bitwarden? Yes. It buys me a workflow that never leaves the terminal, my data on my own disk, and no vendor who can raise the price or sell the company next quarter.

After three password managers

Pass suits people who like the Unix philosophy, one thing done well and wired into everything else. The GPG dependency alone rules it out for plenty of people, and I’d rather say so than sell it to the wrong reader.

For me it was a relief after every overengineered manager before it. Roughly 700 lines of bash, files in a directory, git for sync. Three password managers with a UI, then a shell script. I’m still on the shell script.


Further reading: