Free · Private · Client-side
TOTP Secret Key Generator
Generate Base32-encoded secrets for Time-based One-Time Password (TOTP) authentication. Compatible with Google Authenticator, Authy, Microsoft Authenticator, and other 2FA apps.
Generated values never leave this device.In plain terms: a gaming PC guessing a million passwords per second would need 1,677,978 quintillion times the age of the universe. Even someone renting every cloud server on Earth — a trillion guesses per second — would need 1.7 quintillion times the age of the universe. Nobody is guessing this password; the only realistic risks are it being reused or phished.
Generated secrets
OTPAuth URI (for QR Codes)
Generate a secret firstUse this URI to generate a QR code that users can scan with their authenticator app.
Implementation Examples
import pyotp
# Store this secret securely for each user
secret = "JBSWY3DPEHPK3PXP"
# Generate current TOTP code
totp = pyotp.TOTP(secret)
print(totp.now()) # e.g., "492039"
# Verify a code from user
is_valid = totp.verify("492039")const { authenticator } = require('otplib');
const secret = "JBSWY3DPEHPK3PXP";
// Generate current code
const token = authenticator.generate(secret);
// Verify user's code
const isValid = authenticator.verify({ token: userCode, secret });use Sonata\GoogleAuthenticator\GoogleAuthenticator;
$ga = new GoogleAuthenticator();
$secret = "JBSWY3DPEHPK3PXP";
// Verify user's code
$isValid = $ga->checkCode($secret, $userCode);How TOTP Works
TOTP generates a 6-digit code that changes every 30 seconds. Both the server and the user's authenticator app share the same secret key, allowing them to generate matching codes without network communication.
- Based on HMAC-SHA1 algorithm (RFC 6238)
- Uses Unix timestamp divided by 30-second intervals
- Base32 encoding makes secrets easy to type manually
Bulk Generation
Generate in Terminal
Python
python3 -c "import base64, secrets; print(base64.b32encode(secrets.token_bytes(20)).decode())"OpenSSL + base32
openssl rand -hex 20 | xxd -r -p | base32Node.js (URL-safe variant)
node -e "console.log(require('crypto').randomBytes(20).toString('base64').replace(/[+/=]/g, c => ({'+':'-','/':'_','=':''}[c])))"