Skip to content

Instantly share code, notes, and snippets.

@aslamanver
Created February 11, 2026 16:52
Show Gist options
  • Select an option

  • Save aslamanver/2f2c7fc38fe9007e377a194a6aa01150 to your computer and use it in GitHub Desktop.

Select an option

Save aslamanver/2f2c7fc38fe9007e377a194a6aa01150 to your computer and use it in GitHub Desktop.
Pure Python implementation of TOTP (Time-Based One-Time Password) compatible with Google Authenticator built without any third-party libraries.

Pure Python TOTP (Google Authenticator Compatible)

A minimal, dependency-free implementation of TOTP (Time-Based One-Time Password) written in pure Python using only the standard library.

This script demonstrates how Google Authenticator works on the server side by implementing RFC 6238 manually.

Features

  • ✅ Generate secure random TOTP secrets
  • ✅ Accept custom plain-text secrets (auto-converted to Base32)
  • ✅ Generate otpauth:// URL compatible with Google Authenticator
  • ✅ Manual TOTP generation using:
    • HMAC-SHA1
    • 30-second time step
    • Dynamic truncation
  • ✅ Token verification with configurable clock drift window
  • ✅ No third-party libraries required

What It Demonstrates

  • How TOTP works internally
  • How servers verify Google Authenticator tokens
  • How shared-secret + time-based OTP systems function
  • RFC 6238 compliant implementation

Usage

  1. Run the script.
  2. Enter a custom secret or press Enter to auto-generate one.
  3. Scan the generated otpauth:// URL using Google Authenticator.
  4. Enter the 6-digit code from the app to verify.

Technical Details

  • Algorithm: HMAC-SHA1
  • Digits: 6
  • Period: 30 seconds
  • Clock tolerance: ±1 time window (configurable)

Notes

⚠️ For production use:

  • Always generate cryptographically secure random secrets.
  • Store secrets encrypted at rest.
  • Implement rate limiting for verification attempts.

Pure Python. Zero dependencies. Fully transparent TOTP implementation.

#!/usr/bin/env python3
import base64
import hmac
import hashlib
import time
import urllib.parse
import os
# ----------------------------
# Convert plain text to Base32
# ----------------------------
def plain_text_to_base32(text):
return base64.b32encode(text.encode()).decode('utf-8')
# ----------------------------
# Generate secure random secret
# ----------------------------
def generate_secret(length=20):
random_bytes = os.urandom(length)
return base64.b32encode(random_bytes).decode('utf-8')
# ----------------------------
# Generate otpauth URL
# ----------------------------
def generate_otpauth_url(secret, account_name, issuer_name):
params = {
'secret': secret.replace('=', ''),
'issuer': issuer_name,
'algorithm': 'SHA1',
'digits': 6,
'period': 30
}
return f"otpauth://totp/{urllib.parse.quote(issuer_name)}:{urllib.parse.quote(account_name)}?{urllib.parse.urlencode(params)}"
# ----------------------------
# Generate TOTP
# ----------------------------
def get_totp_token(secret, for_time=None):
if for_time is None:
for_time = int(time.time())
key = base64.b32decode(secret, casefold=True)
time_counter = int(for_time / 30)
msg = time_counter.to_bytes(8, 'big')
h = hmac.new(key, msg, hashlib.sha1).digest()
offset = h[-1] & 0x0F
code = ((h[offset] & 0x7f) << 24 |
(h[offset+1] & 0xff) << 16 |
(h[offset+2] & 0xff) << 8 |
(h[offset+3] & 0xff))
return str(code % 10**6).zfill(6)
# ----------------------------
# Verify TOTP
# ----------------------------
def verify_totp(token, secret, window=1):
current_time = int(time.time())
for w in range(-window, window + 1):
if get_totp_token(secret, current_time + w * 30) == token:
return True
return False
# ----------------------------
# MAIN
# ----------------------------
if __name__ == "__main__":
user_input = input("Enter a secret (leave empty to auto-generate): ").strip()
if user_input:
secret = plain_text_to_base32(user_input)
print("Using your provided secret (converted to Base32).")
else:
secret = generate_secret()
print("Generated secure random secret.")
print("\nTOTP Secret:", secret)
url = generate_otpauth_url(secret, "user@example.com", "MyApp")
print("\nScan this in Google Authenticator:")
print(url)
input("\nPress Enter when ready to verify...")
token = input("Enter 6-digit token: ").strip()
if verify_totp(token, secret):
print("✅ Token is valid!")
else:
print("❌ Invalid token!")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment