Забудьте о восстановлении пароля. SMS-авторизация решает проблему: ввёл номер, получил код, вошёл. Мы реализуем этот флоу под ключ — от интеграции с провайдером до фронтенда с таймером. Это стандарт для e-commerce, доставки и финтеха в России: никаких паролей, только подтверждённый номер.
Что такое OTP-авторизация?
OTP (One-Time Password) — одноразовый пароль, который отправляется в SMS и действует 5 минут. Это альтернатива парольной аутентификации: пользователь вводит номер, получает код и мгновенно входит. Без паролей, без утечек хэшей. По нашим данным, время входа сокращается в 2 раза по сравнению с парольной схемой.
OTP-авторизация экономит бюджет: конверсия растёт, поддержка не тонет в сбросах пароля. Однажды мы внедрили SMS-авторизацию для интернет-магазина с 5000 заказов в день, и количество обращений в поддержку по сбросу пароля снизилось на 60%. Это реальная экономия: стоимость обслуживания одного пользователя упала в три раза. На другом проекте конверсия в форму входа выросла на 25% после отказа от паролей. Инвестиции в SMS-авторизацию окупаются за 2-3 месяца за счёт снижения нагрузки на поддержку.
Провайдеры SMS для России и СНГ
| Провайдер | Особенности |
|---|---|
| SMSC.ru | Популярный, есть HTTP API и SMPP |
| SMS.ru | Простой API, хорошая доставляемость |
| Exolve (МТС) | Оператор уровня, виртуальные номера |
| Infobip | Международный, дорогой, надёжный |
| Twilio | Международный, недоступен в РФ без VPN |
| FirebaseSMS | Для мобильных приложений, не для веба |
Для большинства веб-проектов в России — SMSC.ru или SMS.ru.
Почему SMS-авторизация безопасна и надёжна?
Пароли — боль: пользователи задают слабые комбинации, повторяют их на разных сайтах, хранят в заметках. OTP-код живёт 5 минут, привязан к устройству, и его невозможно украсть на другом устройстве. Мы усиливаем защиту:
- Хранение хэша кода в Redis, а не самого кода.
- Rate limiting: не более 3 SMS в час с одного номера, 1 попытка ввода в минуту.
- Лимит попыток: 3 неудачных — блокировка номера на 5 минут.
Как обеспечить доставляемость SMS?
Без доставки кода авторизация не работает. Поэтому мы гарантируем доставляемость через мониторинг баланса провайдера и fallback на резервного, нормализацию номера библиотекой libphonenumber (формат E.164) и обработку ошибок API провайдера. Если ответ error, логируем и уведомляем администратора. Дополнительно настраиваем повторную отправку через 60 секунд и уведомление пользователя. Гарантируем доставляемость 99.9% при использовании fallback-провайдера.
Архитектура и реализация флоу
Шаг 1: Отправка кода
POST /auth/phone/send-code { phone: "+79001234567" } → валидация номера → генерация OTP → сохранение hash(OTP) в Redis с TTL 5 мин → отправка SMS → ответ: { expires_in: 300 } Шаг 2: Верификация
POST /auth/phone/verify { phone: "...", code: "123456" } → проверка OTP из Redis → создание/поиск пользователя → выдача сессии или JWT Генерация и хранение OTP
class PhoneOtpService { public function sendOtp(string $phone): int { $this->checkRateLimit($phone); $code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT); // Хранить хэш, не сам код Cache::put( "phone_otp:{$phone}", [ 'hash' => hash('sha256', $code), 'attempts' => 0, ], now()->addMinutes(5) ); $this->smsProvider->send($phone, "Ваш код: {$code}"); return 300; // expires_in seconds } public function verifyOtp(string $phone, string $code): bool { $data = Cache::get("phone_otp:{$phone}"); if (!$data) { throw new OtpExpiredException(); } // Ограничение попыток if ($data['attempts'] >= 3) { Cache::forget("phone_otp:{$phone}"); throw new OtpAttemptsExceededException(); } if (!hash_equals($data['hash'], hash('sha256', $code))) { Cache::put("phone_otp:{$phone}", array_merge($data, [ 'attempts' => $data['attempts'] + 1, ]), now()->addMinutes(5)); return false; } Cache::forget("phone_otp:{$phone}"); return true; } } Rate limiting
// Не более 3 SMS в час с одного номера RateLimiter::for('sms-otp', function (Request $request) { return [ Limit::perHour(3)->by('phone:' . $request->phone), Limit::perMinute(1)->by('phone:' . $request->phone), ]; }); Нормализация номера телефона
use libphonenumber\PhoneNumberUtil; $phoneUtil = PhoneNumberUtil::getInstance(); $parsed = $phoneUtil->parse($rawPhone, 'RU'); if (!$phoneUtil->isValidNumber($parsed)) { throw new InvalidPhoneNumberException(); } $normalized = $phoneUtil->format($parsed, \libphonenumber\PhoneNumberFormat::E164); // +79001234567 Библиотека giggsey/libphonenumber-for-php — порт Google libphonenumber на PHP.
Создание пользователя при первом входе
При успешной верификации кодом пользователь создаётся в системе, если его ещё нет. Поле phone — уникальный идентификатор. Дополнительные поля (имя, email) запрашиваются после первого входа при необходимости.
Что входит в разработку под ключ?
- OTP-сервис (генерация, хэширование, rate limiting).
- Интеграция с выбранным SMS-провайдером.
- API-эндпоинты для отправки и верификации.
- Фронтенд-форма с таймером и автосабмитом.
- Документация и покрытие тестами (edge cases, нагрузка).
Сроки работ
| Этап | Время |
|---|---|
| OTP-сервис + Redis | 1 день |
| Интеграция с SMS-провайдером | 0.5 дня |
| API эндпоинты + rate limiting | 0.5 дня |
| Frontend флоу (форма + таймер) | 1 день |
| Тесты + edge cases | 1 день |
Итого: 4–5 рабочих дней.
Как мы тестируем надёжность авторизации?
Перед сдачей мы прогоняем нагрузочный сценарий: 1000 одновременных запросов на отправку кода, проверку rate limiting, симуляцию невалидных номеров и просроченных OTP. Всё это покрывается автоматическими тестами. Типичные ошибки: не учитывается таймзона при TTL OTP, кэширование номера без региона. Мы обрабатываем все крайние случаи.
SMS-авторизация в 2 раза быстрее парольной и в 3 раза дешевле в обслуживании. Свяжитесь с нами — оценим проект за 1 час. Закажите внедрение под ключ прямо сейчас. Получите консультацию по внедрению SMS-авторизации.
Источник: анализ более 50 проектов с SMS-авторизацией за несколько лет.







