TOTP

TOTP generation and management for two-factor authentication.

TOTP via gopass

gopass stores TOTP secrets alongside passwords. The secret is stored as an otpauth:// URI in the entry body.

Generate and copy a TOTP code
gopass otp infra/github -c
Generate TOTP code to stdout
gopass otp infra/github
Add TOTP to an existing entry — edit and add the otpauth URI
gopass edit infra/github

Add a line like:

otpauth://totp/GitHub:evan@domusdigitalis.dev?secret=BASE32SECRET&issuer=GitHub

TOTP via oathtool

oathtool generates TOTP codes from the command line without gopass.

Generate a TOTP code from a base32 secret
oathtool --totp --base32 "BASE32SECRET"
Generate with a specific time step (default is 30 seconds)
oathtool --totp --base32 --time-step-size=30 "BASE32SECRET"
Generate with 8-digit codes (some services use 8 instead of 6)
oathtool --totp --base32 --digits=8 "BASE32SECRET"

TOTP Secret Extraction

Extract the TOTP secret from a gopass entry
gopass show infra/github | grep -oP 'secret=\K[A-Z2-7]+'
Extract from a QR code image — requires zbarimg
zbarimg --quiet --raw qr-code.png

Backup TOTP Secrets

TOTP secrets stored in gopass are backed up with the gopass git store. For additional safety:

Export all TOTP URIs for cold storage
gopass ls -f | while read -r entry; do
    uri=$(gopass show "$entry" 2>/dev/null | grep '^otpauth://')
    [[ -n "$uri" ]] && echo "$entry: $uri"
done | age -e -R ~/.age/recipients/self.txt -o totp-backup.age
This creates a decryptable archive of all TOTP secrets. Store the output in an air-gapped location.

Verify TOTP Configuration

Test that a TOTP code is valid — compare with the service
echo "Generated code: $(gopass otp infra/github)"
echo "Verify this code against the service's 2FA verification page"
Check time synchronization — TOTP depends on accurate system time
timedatectl status | grep -E "synchronized|NTP"

If NTP is not synchronized, TOTP codes will drift and fail authentication.