Разработка авторизации через номер телефона с SMS-кодом
SMS-авторизация выглядит просто: запросил код, получил SMS, ввёл, вошёл. На практике здесь больше edge cases, чем в любом другом методе входа. Неверный формат номера для одной страны, лимиты провайдера SMS, устаревшие коды из-за задержки доставки, подбор кодов без rate limiting — всё это встречается в продакшене.
Ввод и валидация номера телефона
Главная проблема — форматы номеров. Российский номер может быть введён как +7 999 123-45-67, 89991234567, 7 (999) 123-45-67. Сервер должен принимать всё это и нормализовывать в E.164 формат (+79991234567). На клиенте — использовать библиотеку libphonenumber (Google), она же используется в Android системно. Для iOS — PhoneNumberKit (Swift-обёртка над libphonenumber).
Поле ввода номера: keyboardType = .phonePad (iOS) / inputType="phone" (Android). Не numberPad — тогда нет кнопки +. Форматирование номера в реальном времени (маска) реализуем через UITextField delegate / TextWatcher — пользователь видит +7 (999) 123-45-67 по мере ввода, хотя хранится E.164.
Выбор кода страны — либо popup с флагами и поиском (полноценный компонент, 3-5 дней работы), либо жёстко заданная страна если приложение работает только в одном регионе.
OTP-экран: ввод кода
Кастомный OTP-input — 4 или 6 отдельных TextField-а с автоматическим переходом фокуса при вводе каждой цифры. На iOS textContentType = .oneTimeCode включает автоподстановку из SMS — iOS парсит SMS и предлагает код над клавиатурой. Это обязательная функциональность, пользователи ожидают её.
На Android SMS автоматически читается через SmsRetriever API (без запроса разрешений) или SMS User Consent API (с запросом). SmsRetriever требует специального хэша в тексте SMS, который генерируется на основе подписи APK. При смене keystore или debug/release build — хэш меняется, SMS не читается автоматически.
// Android — SmsRetriever
val client = SmsRetriever.getClient(context)
val task = client.startSmsRetriever()
task.addOnSuccessListener {
// Регистрируем BroadcastReceiver на получение SMS
}
Таймер обратного отсчёта для повторной отправки — стандарт 60 секунд. Без него пользователи спамят кнопку «Отправить снова» и засоряют очередь SMS-провайдера. Кнопка недоступна до истечения таймера, потом активируется.
Выбор провайдера SMS
Выбор влияет на доставляемость и стоимость:
| Провайдер | Плюсы | Минусы |
|---|---|---|
| Firebase Auth (SMS) | Бесплатный лимит, простая интеграция | Не работает без Google Services, ограничения в РФ |
| Twilio Verify | Высокая доставляемость, глобальный | Дороже российских провайдеров |
| SMS.ru / SMSC / Devino | Низкая цена для РФ, рублёвые счета | Нет SDK, только HTTP API |
| Яндекс 360 SMS | Интеграция с экосистемой Яндекса | Ограниченный охват |
Для российского рынка чаще всего SMS.ru или SMSC с собственным backend-сервисом — клиент никогда не знает API-ключ провайдера, запрос кода идёт на ваш сервер, сервер отправляет SMS. На backend — rate limiting: не более 3 кодов на номер в час, не более 5 попыток ввода на один код.
Безопасность: что обязательно
- Код хранится на сервере в bcrypt-хэше, не в открытом виде
- TTL кода: 5-10 минут, после истечения — код недействителен
- После 3 неверных попыток ввода — блокировка сессии, нужно запросить новый код
- Rate limiting по IP и по номеру телефона — защита от перебора и дорогостоящей SMS-спам атаки
Сроки: от 1 до 2,5 недель. Включает: UI экранов ввода номера и OTP, интеграция с SMS-провайдером, автоподстановка кода (iOS + Android), тестирование edge cases (невалидный номер, истёкший код, нет SMS).







