python
36 lines · 7 steps
How TOTP two-factor codes work
A from-scratch implementation of time-based one-time passwords, from secret generation to time-window verification.
Explained by
highlit
1import base64
2import hashlib
3import hmac
4import os
5import struct
6import time
7from urllib.parse import quote
8
9
10def generate_secret(length: int = 20) -> str:
11 return base64.b32encode(os.urandom(length)).decode("ascii").rstrip("=")
12
13
14def provisioning_uri(secret: str, account: str, issuer: str) -> str:
15 label = quote(f"{issuer}:{account}")
16 params = f"secret={secret}&issuer={quote(issuer)}&algorithm=SHA1&digits=6&period=30"
17 return f"otpauth://totp/{label}?{params}"
18
19
20def totp(secret: str, digits: int = 6, period: int = 30, at: float | None = None) -> str:
21 padding = "=" * (-len(secret) % 8)
22 key = base64.b32decode(secret.upper() + padding)
23 counter = int((at or time.time()) // period)
24 msg = struct.pack(">Q", counter)
25 digest = hmac.new(key, msg, hashlib.sha1).digest()
26 offset = digest[-1] & 0x0F
27 code = struct.unpack(">I", digest[offset:offset + 4])[0] & 0x7FFFFFFF
28 return str(code % (10 ** digits)).zfill(digits)
29
30
31def verify(secret: str, code: str, window: int = 1) -> bool:
32 now = time.time()
33 return any(
34 hmac.compare_digest(totp(secret, at=now + drift * 30), code)
35 for drift in range(-window, window + 1)
36 )
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1TOTP is just HMAC over a time counter, truncated down to a short numeric code.
- 2Both parties derive the same code from a shared secret without ever exchanging it.
- 3A small verification window absorbs clock skew between the client and server.
Related explainers
python
from fastapi import FastAPI, WebSocket, WebSocketDisconnect app = FastAPI()
Building a WebSocket chat with FastAPI
websockets
broadcast
connection-management
Intermediate
9 steps
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 steps
python
import time import uuid from django.utils.deprecation import MiddlewareMixin
Attaching per-request context in Django
middleware
request lifecycle
multi-tenancy
Intermediate
7 steps
python
import random from typing import Iterator, List
How reservoir sampling picks k items
reservoir-sampling
streaming
randomness
Intermediate
5 steps
python
import secrets from django.contrib.auth import authenticate, login from django.core.cache import cache
Two-factor login with OTP in Django
two-factor-auth
one-time-passwords
caching
Intermediate
9 steps
python
import re from functools import total_ordering from typing import Optional
Parsing and comparing semantic versions
regex
operator-overloading
sorting
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/how-totp-two-factor-codes-work-explained-python-3525/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.