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.