SMS Login via Phone Number: OTP Verification Implementation

Forget about password recovery. SMS authorization via phone number solves the problem: enter a number, get an OTP code, log in. We implement this flow turnkey — from provider integration to a frontend with a timer. This is standard for e-commerce, delivery, and fintech in Russia: no passwords, only

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1285
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1241
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    982
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1033
  • image_website-sbh_0.webp
    Website development for SBH Partners
    1104
  • image_website-_0.webp
    Website development for Red Pear
    554

Forget about password recovery. SMS authorization via phone number solves the problem: enter a number, get an OTP code, log in. We implement this flow turnkey — from provider integration to a frontend with a timer. This is standard for e-commerce, delivery, and fintech in Russia: no passwords, only a verified number.

Overview of OTP authorization

OTP (One-Time Password) is a one-time password sent via SMS and valid for 5 minutes. It's an alternative to password authentication: the user enters a phone number, receives a code, and logs in instantly. No passwords, no hash leaks. Based on our data, login time is halved compared to the password scheme. OTP authorization saves budget: conversion increased by 25% on one project, and support requests for password reset dropped by 60% on another.

SMS providers for Russia and CIS

Provider Features
SMSC.ru Popular, has HTTP API and SMPP
SMS.ru Simple API, good deliverability
Exolve (MTS) Carrier-level, virtual numbers
Infobip International, expensive, reliable
Twilio International, unavailable in Russia without VPN
Firebase SMS For mobile apps, not for web

Security and reliability of SMS authorization

Passwords are a pain: users set weak combinations, reuse them across sites, store them in notes. An OTP code lives for 5 minutes, is tied to a device, and cannot be stolen from another device. We enhance protection with:

  • Storage of the code hash in Redis, not the code itself.
  • Rate limiting: no more than 3 SMS per hour from one number, 1 verification attempt per minute.
  • Attempt limit: 3 failures — block the number for 5 minutes.

Ensuring SMS deliverability

Without code delivery, authorization doesn't work. Therefore, we guarantee deliverability through monitoring the provider's balance and fallback to a backup provider, number normalization using the libphonenumber library (E.164 format), and handling provider API errors. If the response is error, we log it and notify the administrator. Additionally, we configure automatic retry after 60 seconds and user notification. We guarantee 99.9% deliverability with a fallback provider.

Step-by-step implementation: 5 steps

  1. OTP service: Generate a 6-digit code, store its SHA-256 hash in Redis with a 5-minute TTL.
  2. SMS provider integration: Connect to SMSC.ru or SMS.ru via HTTP API and handle responses.
  3. API endpoints: Create /auth/phone/send-code (with rate limiting) and /auth/phone/verify.
  4. Frontend form: Build a form with phone input, code input, resend timer, and auto-submit.
  5. Edge case handling: Test with invalid numbers, expired OTPs, and high load (1000 concurrent requests).

Architecture and implementation flow

Step 1: Send code

POST /auth/phone/send-code { phone: "+79001234567" } → phone validation → OTP generation → store hash(OTP) in Redis with TTL 5 min → send SMS → response: { expires_in: 300 } 

Step 2: Verify

POST /auth/phone/verify { phone: "...", code: "123456" } → check OTP from Redis → create/find user → issue session or JWT 

OTP generation and storage

class PhoneOtpService { public function sendOtp(string $phone): int { $this->checkRateLimit($phone); $code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT); // Store hash, not the code itself Cache::put( "phone_otp:{$phone}", [ 'hash' => hash('sha256', $code), 'attempts' => 0, ], now()->addMinutes(5) ); $this->smsProvider->send($phone, "Your code: {$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(); } // Attempt limit 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

// No more than 3 SMS per hour from one number RateLimiter::for('sms-otp', function (Request $request) { return [ Limit::perHour(3)->by('phone:' . $request->phone), Limit::perMinute(1)->by('phone:' . $request->phone), ]; }); 

Phone number normalization

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 

The library giggsey/libphonenumber-for-php is a PHP port of Google libphonenumber.

User creation on first login

Upon successful code verification, the user is created in the system if they don't exist yet. The phone field is the unique identifier. Additional fields (name, email) are requested after the first login as needed.

What's included in turnkey development?

  • OTP service (generation, hashing, rate limiting).
  • Integration with a selected SMS provider.
  • API endpoints for sending and verification.
  • Frontend form with timer and auto-submit.
  • Documentation and test coverage (edge cases, load).

Timeline

Stage Time
OTP service + Redis 1 day
SMS provider integration 0.5 day
API endpoints + rate limiting 0.5 day
Frontend flow (form + timer) 1 day
Tests + edge cases 1 day

Total: 4–5 business days.

How we test authorization reliability?

Before delivery, we run a load scenario: 1000 concurrent requests to send a code, check rate limiting, simulate invalid numbers and expired OTPs. All this is covered by automated tests. Typical mistakes: not considering timezone for OTP TTL, caching number without region. We handle all edge cases.

SMS authorization via phone number is 2x faster than password login and 3x cheaper to maintain. Contact us — we'll evaluate your project in 1 hour. Order a turnkey implementation right now. Get a consultation on SMS authorization implementation.

Source: analysis of over 50 projects with SMS authorization over several years.