I want to define a log in function in my init script, but I don't want to hardcode my login credentials. I think a good workaround is to have my init script read in my login credentials from a local file and save these values as variables. That way, I can exclude the file from my git index, which keeps my login credentials secure.

Are there any suggestions on this approach, or ways to set an argument to a value that is defined in a file?

For example, I would like to use the following in my init.el:

;; Set up our login variables here:
(setq file-location "~/.emacs.d/.login")
(setq erc-username "default-name")
(setq erc-password "default-password")
(setq erc-url "default-url")
(setq erc-port "default-port")
(defun read-lines (filePath)
  "Return a list of lines of a file at filePath."
    (insert-file-contents filePath)
    (split-string (buffer-string) "\n" t)))
(if (file-exists-p file-location)
    (progn (setq login-credentials (read-lines file-location))
           (setq erc-username (nth 0 login-credentials))
           (setq erc-password (nth 1 login-credentials))
           (setq erc-url (nth 2 login-credentials))
           (setq erc-port (nth 3 login-credentials)))
    (message "No ERC login credentials provided. Please add login credentials as '<username>\n<password>\n<url>\n<port>' in ~/.emacs.d/.login to activate ERC mode."))

;; These message the values from my file correctly.
;; Everything up to this point works as expected
(message erc-username) 
(message erc-password)
(message erc-url)
(message erc-port)

;; Use our login variables here 
;; This doesn't work because the 'quote' function prevents evaluation of my variables, and a 'backquote' did not resolve it either
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(markdown-command "/usr/bin/pandoc")
 '(tls-program (quote ("openssl s_client -connect %h:%p -no_ssl2 -ign_eof -CAfile ~/.ssl/spi_ca.pem -cert ~/.ssl/znc.pem")))
 '(znc-servers (quote ((,erc-url ,erc-port t ((irc\.freenode\.net ,erc-username ,erc-password)))))))
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.

Note that my example uses the znc.el module here. I am modifying the autogenerated code resulting from the Emacs configs in M-x customize-group RET znc RET and M-x customize-variable RET tls-program RET.

My issue with the above code is that the variables are not loading inside my custom-set-variables function above. Loading the proper values from a file seems to work fine, but I can't seem to use them as an argument. I believe this is related to the quote function, which prevents evaluation of its contents. I attempted a 'backquote' (,) to force evaluation, but it is not working either. Any suggestions to fix this bug or offering another approach would be very helpful.

  • Absolute easiest is to use any existing auth access you have and store your values in a secrets.el.gpg file created with your main gpg key and load that. auth takes care of granting access.
    – RichieHH
    May 11, 2021 at 9:28

2 Answers 2


Emacs comes with auth-source.el. I would not try to roll my own version of it.

auth-source makes it easy to read from ~/.authinfo.gpg. Good programs will already support authinfo. A quick search suggests that ERC can use authinfo.

For your random off the shelf MELPA programs you can easily use authinfo to retrieve your password from ~/.authinfo.gpg like this

(with-eval-after-load 'random-mode
  (require 'auth-source)
  (let ((auth (nth 0 (auth-source-search :host "secrets.com"
                                         :requires '(user secret)))))
    (setq random-psk (funcall (plist-get auth :secret))
          random-user (plist-get auth :user))))

where ~/.authinfo.gpg holds the following line:

## Used by random-mode.el
machine secrets.com login rasmus password my-secret-password

Of course the sense of security is a lie. Your password is now stored in plaintext in a variable:

random-psk => "my-secret-password"

But at least it isn't in some git-repo or dropbox somewhere!

If you have got a keyring of some sort you might be able to get credentials from there using the Secret Service API (see (info "(auth) Secret Service API")).


custom-set-variables is weird – I'm not 100% sure it can handle cases like this. You may try (eval `(custom-set-variables … (erc-password … ,(special-value) …) …), but that strikes me as a dirty hack-around.

Just put the extra information in a file with the gpg extension, save it, give a password, and then load the file. You'll have to put the password for the file in when you load it.

For example, create a file sensitive.el.gpg with the contents:

(message "Hello, there!")

Save the file, press (or tab over to) [OK], and give your password. Don't worry – it will ask for confirmation before saving it. Then, in your init file, give

(load "sensitive.el.gpg")

This will load the file on startup, requiring you to enter your password so Emacs can decrypt the file.

If you don't want to enter your password on startup, I'd give the function a name to run manually:

(defun my:keys () (interactive) (load "sensitive.el.gpg"))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.