Integrating password-store with Emacs

Pass might be the perfect password manager.

It's been around for a while. What you might not be aware of how well it can work with Emacs as a backend for auth-sources.

The classic way of storing your username and password in a way that Emacs can understand is to maintain a list of credentials in ~/.authinfo{,.gpg}1 or ~/.netrc. This becomes a pain if you use a password manager though, because now you have to update your password in two places when you change it.

Fortunately there is a library auth-password-store that connects auth-source (used by gnus and tramp, among others) with the Emacs library provided by pass. It's not very well documented at the moment though, so I'll share my experiences here. Note that these entries in the password store don't have to be in the root folder. Mine are all in a directory auth-sources, but you can organise them however you like.

auth-password-store imposes a specific organisation on the files themselves, apparently based on the organisation scheme used by the authors of pass. It looks for the keys host, port, and user. The password is taken to be the first line in the file. You don't need to specify port if some port is passed to auth-pass-backend by the program requesting the secret. For instance, gnus will send port 993 if you've set it up to use an IMAPS server, and smtp-send-it will use port 587 (only useful if the named server is also listening on 587).

For use with tramp:

You need a file with the same user@host format that you would supply to find-file. For instance: /sudo:root@localhost:/etc/file-owned-by-root.

In this case the pass entry will have the form:

$ pass ls auth-sources/root@localhost
<password>
host: localhost
user: root

Even though the it says the user is root, the password here should be your user's sudo password. In the case of a remote server there's no need to allow SSH login as root for this to work, your user just needs to have sudo privileges.

For use with gnus and a local IMAP server:

On my machines I use something like this, but with mbsync instead of offlineimap.

You need a file with the same user@host format you would supply to gnus-select-method. For instance:

(eval-after-load "gnus"
  '(setq gnus-select-method
         ;; there should be a pass entry eqyiel@localhost
         '(nnimap "eqyiel@localhost"
                  (nnimap-address "localhost")
                  (nnimap-stream network))))

In this case the pass entry will have the form:

$ pass ls auth-sources/eqyiel@localhost
<password>
host: localhost
user: eqyiel

If it's not working be sure to check what port you've configured gnus to use and what port your server is listening on.

For use with gnus and a remote IMAP server:

You need a file with the format user@imap-server. Be sure to use the same imap-server as the first argument to nnimap. For instance:

(eval-after-load "gnus"
  '(setq gnus-select-method
         '(nnimap "rkm.id.au"
                  (nnimap-address "rkm.id.au")
                  (nnimap-server-port 993)
                  (nnimap-stream ssl))
         gnus-secondary-select-methods
         '((nnimap "imap.gmail.com"
                   (nnimap-address "imap.gmail.com")
                   (nnimap-server-port 993)
                   (nnimap-stream ssl))
           (nnimap "outlook.office365.com"
                   (nnimap-address "outlook.office365.com")
                   (nnimap-server-port 993)
                   (nnimap-stream ssl)))))

In this case the pass entry will look like this:

$ pass ls auth-sources/eqyiel@imap.gmail.com
<password>
host: imap.gmail.com
user: eqyiel@gmail.com

For use with smtpmail:

You need a file with the format user@smtp-server. Note that the SMTP and IMAP servers may be running on different hosts. For instance, Microsoft Exchange uses smtp.office365.com and outlook.office365.com (IMAP), and Google uses smtp.gmail.com and imap.gmail.com. Fortunately both outlook.office365.com and imap.google.com listen on port 587 so in this case you don't need to maintain two files, but if your server is rejecting your mail as unauthenticated be sure to check this. For an Exchange server (used by my university), the pass entry will look like this:

$ pass ls auth-sources/mahe0054@outlook.office365.com
<password>
host: outlook.office365.com
user: mahe0054@uni.flinders.edu.au

And for Gmail:

$ pass edit auth-sources/eqyiel@imap.gmail.com
<password>
host: imap.gmail.com
user: eqyiel@gmail.com

If you're using this advice from emacswiki the smtp-server and host field must match the third argument to an account in smtp-accounts. For example:

(defvar smtp-accounts
  '((ssl "eqyiel@gmail.com" "imap.gmail.com" 587 "eqyiel@gmail.com" nil)
    (ssl "mahe0054@uni.flinders.edu.au" "outlook.office365.com" 587
         "mahe0054@uni.flinders.edu.au" nil)))

It's great being able to manage these all in one place. Now, if only all web services had a standard API for changing passwords!