Why OTPs deserve special care
A one-time passcode is the most time-sensitive message you send. The user is staring at a screen waiting for it, so delay costs you a sign-up or a sale. It is also the message attackers target, because anyone who can trigger or intercept passcodes can abuse your system or run up your bill. A good OTP flow therefore balances three goals: speed, clarity and security.
Delivery
- Use a registered transactional template and a dedicated sender ID
- Keep the text short enough for one segment, as explained in the segments guide
- Put the code early in the message so it shows in the notification preview
- Avoid links, which can trigger filters and delay delivery
- Send OTPs on a route separate from promotional traffic
- Keep your registered text identical to what you send, as described in the DLT checklist
A good OTP message
“123456 is your YourBrand verification code. It is valid for 5 minutes. Do not share it with anyone.” The code comes first, the brand is named, the lifetime is stated and the warning against sharing reduces social-engineering fraud.
Security
- Use a short expiry. Five minutes or less. Longer lifetimes give attackers more time
- Rate limit requests. Cap requests per number, per account and per IP address
- Limit attempts. Lock the code after a few wrong tries and require a new request
- Make it single use. Invalidate the code after one successful use
- Generate securely. Use a cryptographically secure random generator, never a predictable sequence
- Never log codes. Keep codes out of logs, analytics and error messages
Protecting against fraud
Attackers use OTP endpoints in two main ways. In traffic pumping they trigger many sends to numbers in countries with high termination rates, hoping to share in the revenue. In enumeration and flooding they send many codes to one victim to annoy them or to hide a fraudulent transaction.
- Put a CAPTCHA or proof-of-work check in front of the send endpoint
- Allow-list the countries you serve and block the rest
- Limit sends per number per hour and per day
- Alert on spikes in volume or in spend per country
- Require the user to be signed in or hold a session before requesting a code where possible
User experience
Small design choices make a large difference to success rates.
| Choice | Recommendation | Why |
|---|---|---|
| Code length | Six digits | Balance of security and ease |
| Resend | Offer after 30 seconds | Gives time without frustration |
| Fallback | Voice call or email after repeated failure | Reaches users with SMS problems |
| Autofill | Use the platform one-time-code format where supported | Removes typing |
| Errors | Say the code is wrong or expired, not why | Avoids helping attackers |
Monitoring
- Track the share of codes verified within five minutes
- Track delivery time at the median and at the 95th percentile
- Track the cost per verified user
- Alert if the verification rate drops, which often signals a delivery problem
Implementation outline
A secure OTP service needs only a few tables and a short sequence. When a user requests a code, check the rate limits first. Generate the code with a secure random generator and store only a salted hash with the expiry time, attempt count and the destination number. Send the message and record the message ID against the request, so you can trace a complaint later. When the user submits a code, hash it, compare it in constant time, check expiry and attempts and mark it used. On any failure return the same generic response. Remove old records on a schedule.
Test the flow with deliberately hostile inputs: a code reused twice, a code after expiry, a thousand rapid requests, a number from a blocked country. Each should fail safely and leave a clear log entry.
Fallback channels
No single channel reaches everyone. Offer an alternative after a resend: a voice call that reads the code, an email or a WhatsApp authentication template. Choose the order by cost and reach. Voice is slower and more expensive but works on any phone. Email is cheap but depends on the user reading it quickly. Whatever you choose, apply the same expiry, rate limits and attempt caps, so a fallback does not become the weak point.
Measuring OTP quality
Define a few numbers and review them weekly. Conversion is the share of requested codes that are successfully verified. Time to verify is how long that takes at the median and tail. Cost per verification shows whether fraud or excess resends are inflating spend. A fall in conversion with no change in volume almost always points to delivery, so check the failure and delay dashboards from the troubleshooting guide first.
Legal and privacy points
An OTP message is personal data in transit. Do not include more information than needed, such as account balances or names. Keep stored hashes only as long as the code is valid. Tell users in your privacy notice that you send verification messages and how you use their number. Confirm the details that apply to your market with your legal adviser.
Testing before launch
Run a short test plan before any OTP flow goes live. Send codes to numbers on several operators and measure delivery time. Check the message on both Android and iOS notification previews. Request codes quickly in a row to confirm the rate limit works. Use an expired code and a reused code and confirm each is refused. Finally switch off your primary route in a test environment and confirm the fallback takes over. Keep the results with your release notes.
Review and ownership
Assign a named owner to this area and put a review on the calendar every quarter. At each review, check the metrics described above, read the last quarter's incidents and update the runbook with anything you learned. Short, regular reviews keep small drifts from turning into outages, and they make onboarding new team members far easier because the current practice is written down in one place.
Further reading
- NIST SP 800-63B, Digital Identity Guidelines: Authentication
- RFC 6238, TOTP, for app-based alternatives to SMS
- Telnxo guide: Why messages fail or arrive late
Frequently asked questions
What if the OTP does not arrive?
Offer a resend after a short wait and a voice or email fallback.
How long should a code be valid?
Five minutes or less is a common choice. Shorter is safer.
Should OTPs contain links?
Avoid them. Links can delay delivery and are often used in phishing.
Is SMS OTP secure enough?
It is widely used and better than a password alone. For high-risk actions combine it with other factors or use app-based codes.