Skip to content

Persistent sudo Touch ID Authentication on macOS

It’s been five years since the first launch of a Touch ID capable Macbook. In case you’re out of the loop, Touch ID is also available as a built-in PAM module. Unfortunately it’s not enabled for sudo by default, so people need to add a entry in the /etc/pam.d/sudo file.

Sounds perfectly no problem, unless you hit a system upgrade. Since modern macOS performs image-based updates, the system volume is overwritten every time it’s updated. Including /etc/pam.d/sudo. As a result, I had to manually manipulate the file for every update.

I was officially tired of that, and looked into if there’s any existing solutions. Someone at Hacker News suggested to add a shell alias to automatically add the entry, or more straightforward, wrap the sudo function, check every time if is enabled, and add the entry to /etc/pam.d/sudo if not. Good enough, but I think we don’t have to mess with the shell configurations just for this.

I created persistent_pam_tid. It’s a macOS LaunchDaemon that calls a script to check /etc/pam.d/sudo at every system startup, and adds if it’s not present in the file:

if ! grep '' /etc/pam.d/sudo --silent; then
  sed -i -e '1s;^;auth       sufficient\n;' /etc/pam.d/sudo

While studying launchd.plist, this documentation has made exceptional use, and it was simple enough to construct this launchd configuration:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "">
<plist version="1.0">







To install a launch daemon, move the definition file to /Library/LaunchDaemons/ and run:

sudo launchctl load -w <path>

sudo is required for launch daemons, since they are either run as root or any other arbitrary user specified in the definitions file. The flag -w enables the service if it’s disabled.

Now the daemon is loaded, yet since RunAtLoad is set to true, the pam_tid_installer is called (as root).

Every time the system boots, launchd scans the launch daemons directories and loads those daemons which are not disabled. So our daemon will be run every time system starts.