Requiring a second proof beyond the password, usually a short code sent to your phone, so a stolen password alone isn't enough.
Why it exists
A password alone can be guessed, phished, or reused from another breach, and then the account is gone. Relying on one secret is fragile. OTP and two-factor authentication exist to require a second, short-lived proof such as a code to your phone, so a stolen password on its own is no longer enough to get in.
How it actually works
Passwords leak. Two-factor authentication adds a second step: after the password, you enter a one-time code (an OTP) sent by SMS or generated by an app. An attacker would need both your password and your phone.
In many markets, especially for payments, OTP by SMS is the norm and often legally required. It meaningfully cuts account takeovers.
A senior PM walks you through it
A junior PM, stuck
Support escalated a wave of "my code never arrived" complaints, so I asked the dev what is going on with SMS. Instead of an answer he pasted eleven lines from the OTP service for one of the customers and said "the code arrived, read it." I can see the customer's number and a lot of timestamps, but I cannot tell whether we have a delivery problem or something else.
This is the OTP service's own diary for one login attempt, and it settles the argument you are about to have with the SMS vendor. Every line is the same four parts, a timestamp, a level, the service name otp, then plain words about the code's life: generated, sent, verified, rejected. You can learn to read this in five minutes, and it will show you that "never arrived" is not what happened here. Here are the lines exactly as he sent them, one phone number, about two minutes. Read the timestamps down the left once, then take the steps with me.
OTP service log, one phone number, Friday evening login
2026-03-06T21:05:20ZINFOotp verify ok code_id=c_4472 user=u_88231
Click a step to see the lines it points at.
Mistakes I've seen
Reading "never arrived" as gospel and opening a vendor escalation. This log shows delivery confirmed at 94 seconds, so the real problem is latency and the resend flow, and a vendor ticket about non-delivery goes nowhere.
Fixing it by making the code valid_for longer. The first code was killed by a resend at two minutes, not by the 300s clock, so a longer window changes nothing here.
Not counting how often the late text plus a resend collide. One rejected login looks harmless, but if latency is high for a whole evening, every impatient user manufactures their own OTP_EXPIRED.
Speccing the resend button without deciding what it does to the old code. If resend must invalidate the previous code, the UI has to say so, or users keep typing a code the system already threw away.
Filing the follow-up without the code_ids and timestamps. "OTP is broken" makes the engineer start over, while "c_4471 delivered 94s late, superseded by c_4472 at 21:04:20, rejected as EXPIRED" points straight at these lines.
Reply in the thread with: "Traced c_4471 for u_88231. It was delivered 94 seconds late, but the customer had already tapped resend at 21:04:20, which invalidated it, so the 'expired' rejection is a superseded code, not a timeout. The fix is delivery latency and what resend does to the old code, not a longer expiry." You followed one code_id through send, resend, and reject, and turned "never arrived" into a specific cause.
Where a PM meets this
2FA reduces fraud but adds friction and cost (SMS isn't free) and fails when users change numbers. Where to require it is a product decision.
OTP delivery delays are a real support issue; "my code never arrived" flows need designing.
Hear it in a meeting
"Let's require OTP only on new devices, not every login."