This article started from a tweet.
Someone on Twitter said they "lowkey want to understand the technology behind Google Authenticator" and I dropped a quick reply - explaining that it's basically TOTP: your device and the server share a secret key, both compute a code using HMAC-SHA1 and the current 30-second time window. No network calls. No "previous code." Same secret + same time slice = same 6-digit code.
That reply got some traction, and a few people DM me for a deeper breakdown. So here we are.
If you've ever wondered how your phone generates the exact same 6-digit code the server expects - with no internet request, no sync, nothing - this one's for you.
The Problem With Passwords
Passwords are static. Once someone has it, they have it forever - or until you change it. Even with a strong password, you're one phishing attack or database breach away from compromise.
Two-factor authentication fixes this by adding something that changes. But here's the catch - if your phone needs to call a server every time to get a new code, that's a point of failure. What happens when you're offline? On a plane? In a basement with no signal?
This is where TOTP comes in.
TOTP - Time-based One-Time Password
TOTP is defined in RFC 6238, but don't let the RFC scare you. The core idea is dead simple:
Both your phone and the server share a secret. They both know the current time. They both do the same math. They both get the same answer.
That's it. No network calls. No synchronization requests. Just two parties doing identical calculations independently.
The Setup - That QR Code You Scanned
When you enable 2FA on any service, they show you a QR code. That QR code contains a URL that looks something like this:
otpauth://totp/MyService:yusuf@yusadolat.me?secret=JBSWY3DPEHPK3PXP&issuer=MyService
The important part is the secret. This is a base32-encoded string that both your authenticator app and the server will store. This shared secret is the foundation of everything.
You scan it once. Your app saves it. The server saves it. They never exchange it again.
The Math - How Codes Get Generated
Every 30 seconds, both sides perform this calculation:
Step 1: Get the current time window
Take the current Unix timestamp and divide by 30. Floor it.
time_step = floor(current_unix_time / 30)
Right now, as I write this, the Unix timestamp is around 1733644800. Divided by 30, floored, gives us 57788160. This number changes every 30 seconds.
Step 2: Run HMAC-SHA1
Feed the time step and the shared secret into HMAC-SHA1:
hmac_result = HMAC-SHA1(secret, time_step)
This produces a 20-byte hash. It looks like random garbage, but it's deterministic - same inputs always give same outputs.
Step 3: Dynamic Truncation
20 bytes is too long for humans to type. So we extract 4 bytes from a specific position (determined by the last nibble of the hash), convert to an integer, and take modulo 1,000,000.
offset = hmac_result[19] & 0x0fcode = (hmac_result[offset:offset+4] & 0x7fffffff) % 1000000
Boom. You have your 6-digit code.
Why This Is Actually Clever
Think about what just happened:
No network needed - Your phone doesn't call anyone. The server doesn't push anything. Both just compute.
Codes expire automatically - Because time moves forward, old codes become useless. Even if someone shoulder-surfs your code, they have maybe 30 seconds to use it.
Can't predict future codes - Without the secret, you can't compute tomorrow's codes. The HMAC function is one-way.
Replay attacks fail - Use a code once, the server marks that time window as used. Try it again, rejected.
When Things Go Wrong
The system assumes both parties agree on what time it is. This is usually fine - your phone syncs with NTP servers, and servers have accurate clocks.
But I've seen people with phones that have "manual time" set, drifting by minutes. Their codes stop working and they have no idea why. The server is computing codes for 10:45:00, their phone is computing for 10:43:00. Different time windows, different codes.
Most implementations allow a small tolerance - they'll accept codes from one time window before or after. But drift too far and you're locked out.
The Recovery Code Situation
Those backup codes you're told to save somewhere? They're not TOTP. They're just long random strings stored in a database. Use one, it gets deleted. No time component, no algorithm - just a simple lookup.
Save them. Seriously. Losing access to your authenticator without backup codes is a special kind of pain.
Show Me The Code
Here's a minimal Python implementation to make this concrete:
import hmacimport hashlibimport structimport timeimport base64def generate_totp(secret: str) -> str: # Decode the base32 secret key = base64.b32decode(secret.upper()) # Get current time step (30-second window) time_step = int(time.time()) // 30 # Pack as big-endian 8-byte integer time_bytes = struct.pack('>Q', time_step) # Compute HMAC-SHA1 hmac_hash = hmac.new(key, time_bytes, hashlib.sha1).digest() # Dynamic truncation offset = hmac_hash[-1] & 0x0f code_int = struct.unpack('>I', hmac_hash[offset:offset+4])[0] code_int &= 0x7fffffff code = code_int % 1000000 return f'{code:06d}'# Test itsecret = 'JBSWY3DPEHPK3PXP' # Example secret, This is what you add setup key on Google Authprint(generate_totp(secret))
Want to see it work in real-time? Here's how to test:
Open Google Authenticator (or any TOTP app)
Tap the + button to add a new account
Select "Enter a setup key"
Enter any name (e.g., "TOTP Test")
For the key, enter:
JBSWY3DPEHPK3PXPMake sure it's set to Time-based
Save it
Now run the Python script. The 6-digit code it prints should match what's showing in your authenticator app. If you're a few seconds off, wait for the next 30-second window and try again.
Wrapping Up
There's no cloud magic happening when your authenticator generates codes. It's just math - the same math running independently on your device and the server, anchored to the same clock.
Understanding this changes how you think about 2FA. It's not some opaque security feature. It's a clever application of cryptographic primitives that's been working reliably for over a decade.
Next time you punch in those 6 digits, you'll know exactly what's happening behind the scenes.
If you found this useful, I write about DevOps, security, and cloud infrastructure. Connect with me on Twitter @Yusadolat.
]]>

Top comments (2)
Wow! Brilliantly explained.
Thank you so much for this detailed explanation.
Hello