OATHTool
oathtool is a command-line tool and Python library for generating one-time passwords, supporting both HOTP (HMAC-based) and TOTP (Time-based) algorithms. The current version is 2.4.0, and it maintains a stable, albeit infrequent, release schedule, focusing on reliability and security.
Common errors
-
AttributeError: module 'oathtool' has no attribute 'TOTP'
cause You are trying to import TOTP directly from the top-level `oathtool` module.fixImport TOTP from its specific submodule: `from oathtool.totp import TOTP`. -
ValueError: Invalid base32 secret
cause The secret string provided to `TOTP` or `HOTP` constructor is not a valid base32 encoding.fixVerify that your secret key is a correctly formatted base32 string. It should only contain A-Z, 2-7, and optionally padding '=' characters. -
TypeError: oathtool.totp.TOTP.__init__() missing 1 required positional argument: 'key'
cause No secret key was provided when initializing the `TOTP` or `HOTP` object.fixPass your base32-encoded secret key as the first argument to the constructor, e.g., `TOTP('YOUR_SECRET_KEY')`.
Warnings
- gotcha Secret keys are typically expected to be base32-encoded strings. While `oathtool` can often handle raw bytes or attempt decoding, providing an invalid base32 string will lead to errors.
- gotcha Hardcoding secret keys directly in your code is a significant security risk. Anyone with access to your code can compromise your accounts.
- gotcha When using HOTP, the 'counter' value must be meticulously synchronized between the client (your application) and the server. Desynchronization will lead to invalid codes.
Install
-
pip install oathtool -
pip install 'oathtool[cli]'
Imports
- TOTP
import oathtool; oathtool.TOTP
from oathtool.totp import TOTP
- HOTP
import oathtool; oathtool.HOTP
from oathtool.hotp import HOTP
Quickstart
import os
from oathtool.totp import TOTP
# Retrieve your base32-encoded secret key from an environment variable.
# Example: 'JBSWY3DPEHPK3PXP' (this is a placeholder, use your actual secret)
secret_base32 = os.environ.get('OATHTOOL_SECRET', 'JBSWY3DPEHPK3PXP')
if secret_base32 == 'JBSWY3DPEHPK3PXP':
print("WARNING: Using a placeholder secret. Set OATHTOOL_SECRET environment variable for actual use.")
try:
# Initialize the TOTP generator with your secret.
# oathtool expects the secret to be base32-encoded or raw bytes.
# If a base32 string is provided, it will be decoded automatically.
totp = TOTP(secret_base32)
# Generate the current time-based one-time password.
current_otp = totp.code()
print(f"Generated TOTP: {current_otp}")
# You can also get the remaining time until the next code.
# time_left = totp.time_left()
# print(f"Time left until next code: {time_left} seconds")
except Exception as e:
print(f"Error generating OTP: {e}")
print("Ensure your OATHTOOL_SECRET is a valid base32 encoded string.")