Phone Number Authentication with SMS Code Development
SMS login looks simple: request a code, receive SMS, enter, you're in. In practice, there are more edge cases than in any other login method. Incorrect number format for a country, SMS provider limits, stale codes due to delivery delays, code brute-forcing without rate limiting — all of these occur in production. Over 5+ years we've implemented SMS auth in 30+ projects and know how to navigate every pitfall.
Phone Number Input and Validation
The main issue is number formats. A Russian number can be entered as +7 999 123-45-67, 89991234567, 7 (999) 123-45-67. The server should accept all these and normalize to E.164 format (+79991234567). On the client — use the libphonenumber library (Google), which is also used system-wide on Android. For iOS — PhoneNumberKit (Swift wrapper around libphonenumber).
The phone input field: keyboardType = .phonePad (iOS) / inputType="phone" (Android). Not numberPad — then the + button is missing. Real-time formatting (mask) we implement via UITextField delegate / TextWatcher — the user sees +7 (999) 123-45-67 as they type, though it's stored as E.164.
Country code selection — either a popup with flags and search (full component, 3–5 days work) or a fixed country if the app works only in one region.
OTP Screen: Code Input
Custom OTP input — 4 or 6 separate TextFields with automatic focus transition on each digit entry. On iOS textContentType = .oneTimeCode enables auto-fill from SMS — iOS parses the SMS and offers the code above the keyboard. This is mandatory functionality; users expect it.
On Android, SMS is automatically read via SmsRetriever API (no permission request) or SMS User Consent API (with permission). SmsRetriever requires a special hash in the SMS text, generated based on the APK signature. When the keystore changes or debug/release build — the hash changes, SMS is not automatically read.
// Android — SmsRetriever val client = SmsRetriever.getClient(context) val task = client.startSmsRetriever() task.addOnSuccessListener { // Register BroadcastReceiver to receive SMS } Countdown timer for resend — standard 60 seconds. Without it, users spam the "Resend" button and flood the SMS provider queue. The button is disabled until the timer expires, then re-enabled.
Which SMS Provider to Choose for the Russian Market?
The choice affects deliverability and cost. Firebase Auth — free tier, simple integration, but doesn't work without Google Services and has disruptions in Russia. Twilio Verify — high global deliverability, but more expensive than Russian providers and inconvenient for ruble accounts. SMS.ru / SMSC / Devino — low price for Russia, ruble accounts, but no SDK, only HTTP API. For the Russian market, SMS.ru or SMSC is most often chosen with a custom backend service: the client never knows the provider API key, the code request goes to your server, the server sends the SMS. On the backend — rate limiting: no more than 3 codes per number per hour, no more than 5 input attempts per code.
What to Do If SMS Doesn't Arrive?
First, check the provider's rate limits — often the problem is exceeding limits. Second, provide an alternative channel: a voice call with code (TTS). Third, increase the TTL of the code to 10 minutes and show a countdown timer so the user doesn't press resend. As a last resort, connect a backup provider. In our practice, this solved the issue in 95% of cases.
Security: What Is Mandatory
- The code is stored on the server as a bcrypt hash, not plaintext.
- Code TTL: 5–10 minutes, after expiry the code is invalid.
- After 3 incorrect attempts — session lockout, need to request a new code.
- Rate limiting by IP and phone number — protection from brute force and costly SMS spam attacks.
What's Included in the Work
- UI screens: number input with mask, OTP field with auto-fill (iOS/Android)
- Integration with SMS provider (Firebase, Twilio, SMS.ru, SMSC) via your backend
- Configuration of rate limiting and security on the server
- Development of an alternative channel (voice call) — optional
- Testing edge cases: invalid number, expired code, missing SMS, network change
- API and configuration documentation
Timelines and Experience
Timelines: from 1 to 2.5 weeks depending on the number of providers and UI complexity. Over 5 years in mobile development, completed 30+ projects with authentication. We use proven solutions — Firebase, Twilio, custom backend microservices. We guarantee security according to OWASP Mobile Top 10.
To discuss your project details and get a consultation, contact us — we will find the best solution for your stack and region.







