Shav Vimalendiran
BlogWiki ↗
  • The Last MoatsJul 7, 2026
  • The Tech FrontierJul 6, 2026
  • The Trust BarrierJul 4, 2026
  • I Open-Sourced My Coding Agents' MemoryJun 24, 2026
  • How I Gave My Coding Agents Persistent MemoryMar 12, 2026
  • Multi‑Agent Web Exploration with Shared Graph MemoryFeb 19, 2026
  • Our Lessons from Building Production Voice AIJan 11, 2026
  • Reinforcement Learning, Memory and LawDec 10, 2025
  • Automating Secret ManagementOct 23, 2025
  • The Knowledge LayerOct 5, 2025
  • OTel Sidecars on FargateSep 11, 2025
  • Git Disasters and Process DebtSep 7, 2025
  • Is Code Rotting Due To AI?Sep 3, 2025
  • The Integration IllusionAug 30, 2025
  • When MCP FailsAug 26, 2025
  • Context EngineeringAug 22, 2025
  • Stop Email Spoofing with DMARCAug 5, 2025
  • SOTA Embedding Retrieval: Gemini + pgvector for Production ChatJul 21, 2025
  • Agentic Design PatternsJun 21, 2025
  • Building AI Agents for Automated PodcastsJan 1, 2025
  • Rediscovering CursorDec 2, 2024
  • GraphRAG > Traditional Vector RAGAug 8, 2024
  • Cultural Bias in LLMsJul 20, 2024
  • Mapping out the AI Landscape with Topic ModellingJul 7, 2024
  • Sustainable Cloud Computing: Carbon-Aware AIJun 27, 2024
  • Defensive Technology for the Next Decade of AIJun 24, 2024
  • Situational Awareness: The Decade AheadJun 13, 2024
  • Mechanistic Interpretability: A SurveyJun 7, 2024
  • Why I Left UbuntuMay 24, 2024
  • Multi-Agent CollaborationApr 16, 2024
  • Building Better Retrieval SystemsMar 28, 2024
  • Building an Automated Newsletter-to-Summary Pipeline with Zapier AI Actions vs AWS SES & LambdaFeb 3, 2024
  • Local AI Image GenerationDec 15, 2023
  • Deploying a Distributed Ray Python Server with Kubernetes, EKS & KubeRayNov 15, 2023
  • Making the Switch to Linux for DevelopmentOct 24, 2023
  • Scaling Options Pricing with RayOct 1, 2023
  • The Async Worker PoolSep 23, 2023
  • Browser Fingerprinting: Introducing My First NPM PackageSep 8, 2023
  • Reading Data from @socket.io/redis-emitter without Using a Socket.io ClientJul 6, 2023
  • Socket.io Middleware for Redux Store IntegrationJul 1, 2023
  • Sharing TypeScript Code Between Microservices: A Guide Using Git SubmodulesApr 21, 2023
  • Efficient Dataset Storage: Beyond CSVsFeb 3, 2023
  • Why I switched from Plain React to Next.js 13Nov 8, 2022
  • Deploy & Scale Socket.io Containers in ECS with ElasticacheNov 3, 2022
  • ›Implementing TOTP Authentication in Python using PyOTPSep 13, 2022
  • Simplifying Lambda Layer ARNs and Creating Custom Layers in AWSSep 9, 2022
  • TimeScaleDB Deployment: Docker Containers and EC2 SetupJun 23, 2022
  • How to SSH into an EC2 Instance Using PuTTYDec 16, 2021
Loading post…

In This Post

Understanding TOTP AuthenticationBuilding the Authentication ClassAuthentication Flow ImplementationUser Registration ProcessQR Code GenerationTOTP AlgorithmValidation ProcessHandling Time SynchronizationBest Practices and Security Considerations
Published: September 13, 2022
PreviousNext

Implementing TOTP Authentication in Python using PyOTP

Two-factor authentication (2FA) has become essential for securing user accounts in modern applications. Among the various 2FA methods available, Time-Based One-Time Passwords (TOTP) offer an excellent balance of security and user experience.

In this guide, I'll walk you through implementing TOTP authentication in Python using PyOTP, a powerful library that seamlessly integrates with popular authenticator apps like Google Authenticator and Authy. We'll build a complete authentication system that generates temporary passwords expiring every 30-240 seconds.

Understanding TOTP Authentication

PyOTP is a Python library specifically designed for generating and verifying one-time passwords. It enables you to implement robust two-factor or multi-factor authentication methods in web applications and other systems requiring secure user login.

The beauty of TOTP lies in its time-based nature - passwords are generated using a combination of a shared secret key and the current timestamp, ensuring each code is unique and expires quickly.

Building the Authentication Class

Let's create a comprehensive auth_2FA class that handles all our TOTP operations:

auth_2FA.py
import pyotp
import qrcode
 
class auth_2FA:
    """Class for verifying one-time passwords (TOTP: Time-Based One-Time Password Algorithm).
    For use with Google Authenticator and other OTP apps."""
 
    @staticmethod
    def secret_key_gen():
        """Generate a 32-character base32 secret, compatible with Google Authenticator
        and other OTP apps."""
        return pyotp.random_base32()
 
    def gen_qr(self, secret_key: str):
        """Generate provisioning URIs for use with the QR Code scanner built into MFA
        client apps - works with Google Authenticator iPhone and Android app."""
        provisioning_uri = pyotp.totp.TOTP(secret_key).provisioning_uri(
            name='user@example.com',
            issuer_name='YourApp'
        )
        img = qrcode.make(provisioning_uri)
        img.save("./totp_qr.png")
 
    def totp_gen(self, secret_key: str):
        """Generate the Time-Based One-Time Password. Used for development testing."""
        totp = pyotp.TOTP(secret_key)
        current_otp = totp.now()
        print("Current OTP:", current_otp)
        return current_otp
 
    def validate_otp(self, code_to_verify: str, secret_key: str):
        """Verify TOTP for current time. Returns True or False."""
        totp = pyotp.TOTP(secret_key)
        return totp.verify(code_to_verify)

Authentication Flow Implementation

Now that we have our core methods, let's understand the complete authentication workflow:

User Registration Process

When a user registers for an account on your application, you'll store their hashed password securely in the database, just as you would with any regular password-based authentication system. Additionally, generate a Base32 secret using secret_key_gen() to enable TOTP for the user, and save this in your users table.

QR Code Generation

PyOTP works seamlessly with Google Authenticator, Authy, and other OTP apps. The library includes the ability to generate provisioning URIs for use with QR code scanners built into these MFA client apps. The gen_qr() method handles this by using the qrcode module to generate a scannable QR code that users can add to their authenticator app.

TOTP Algorithm

The TOTP algorithm uses HMAC-SHA1 (Hash-based Message Authentication Code with SHA-1) to generate one-time passwords. The algorithm takes the secret key and the current timestamp as input, producing a unique, time-based OTP that changes every 30 seconds.

Validation Process

When users attempt to log in, they provide both their regular password and the current one-time password from their authenticator app. The server uses the stored secret key associated with the user's account and the current time to calculate the expected OTP, then compares it with the entered OTP for authentication.

Handling Time Synchronization

To account for slight variations in time between the server and the user's device, a small grace period is typically allowed during OTP verification. If the current OTP is not accepted, the server may check the OTPs for the previous and next time steps as well, accommodating minor time differences.

Best Practices and Security Considerations

As a developer, you should implement a backup mechanism for users to regain access if they lose their TOTP device. This could include:

  • Backup codes: Pre-generated single-use codes
  • Alternative 2FA methods: SMS or email verification
  • Account recovery process: Secure identity verification procedure

These backup options ensure users aren't permanently locked out of their accounts while maintaining security standards.


Loading comments...
PreviousDeploy & Scale Socket.io Containers in ECS with ElasticacheNextSimplifying Lambda Layer ARNs and Creating Custom Layers in AWS

Be the first to share your thoughts!