Mobile App Login: SMS OTP, Sign in with Apple and Google
Practice4 minInnovialabs editorial team
In short
For apps in Central Asia and the CIS, a sound default is phone number with SMS OTP plus Google and Apple sign-in, with tokens in Keychain/Keystore and sessions renewed by a refresh token.
The short answer
There is no universal method, but a solid default setup for most apps in Uzbekistan and the CIS looks like this:
- Phone number + one-time code as the main login, since everyone has a phone and businesses often need it anyway (delivery, courier calls).
- Sign in with Google and Sign in with Apple for one-tap login without typing a code.
- A short-lived access token and a long-lived refresh token, kept in the system's secure storage.
The rest is about the details teams most often get wrong.
Comparing login methods
| Method | Pros | Cons |
|---|---|---|
| SMS OTP | Familiar, phone verified at once | Paid messages, delivery delays, fraud |
| One tap on Android, no passwords | Not every iOS user has a Google account | |
| Apple | One tap on iOS, email can be hidden | No phone number, email may be a relay address |
| Email + password | No external dependencies | Forgotten passwords, more friction |
| Email magic link | Passwordless | Awkward switching between mail and app |
Apple's Sign in with Apple rule
If an iOS app offers login through third-party services (Google, Facebook and so on), the App Store Review Guidelines require an equivalent privacy-focused option as well: one that collects only name and email, lets users hide their email and is not used for ad tracking. Sign in with Apple meets these requirements, so in practice teams simply add it next to Google.
The rule does not apply to apps that use only the company's own accounts (for example phone + SMS), and to some enterprise and education scenarios. The wording changes over time, so check the current version of section 4.8 of Apple's guidelines.
Two more requirements people forget:
- The app must let users delete their account.
- With Apple sign-in, the user's name arrives only on the first authorization, so store it on the server right away.
SMS OTP: cost and fraud
Every SMS costs money, and the price depends on country, carrier and aggregator. The main threat is SMS pumping: bots request codes en masse to numbers whose owners earn a share of the traffic revenue. You pay the bill.
How to protect yourself:
- Rate limits per number, device and IP: a few requests per window, with growing delays between retries.
- Country allowlist. If you only operate in Uzbekistan, do not send SMS to other country codes.
- Device integrity checks, Play Integrity on Android and App Attest on iOS, so requests come from your real app.
- Monitoring: alert on sudden spikes in sends or a low share of verified codes.
- Alternative channels: delivering codes via a messenger or flash call can be cheaper, but keep SMS as a fallback.
The code itself: 4-6 digits, valid for a few minutes, a limited number of attempts, stored on the server only as a hash. Enable code autofill from SMS (SMS Retriever on Android, oneTimeCode on iOS).
Token storage and session refresh
- Access token: short-lived, sent with every request.
- Refresh token: long-lived, used only to get a new pair. Issue a new refresh token on every refresh and revoke the old one (rotation).
- Store tokens in the Keychain on iOS and in storage encrypted with a key from the Android Keystore. Flutter has
flutter_secure_storage; React Native hasreact-native-keychainorexpo-secure-store. Do not use plainSharedPreferences,UserDefaultsorAsyncStorage. - Refresh with a single request: if several calls get a 401 at once, the others wait for the first refresh to finish.
- Keep a per-device session list on the server so users can sign out everywhere and you can revoke a stolen token.
Common mistakes
- Sending SMS with no rate limits or country checks.
- Keeping tokens in unprotected storage.
- No account linking: a person signs in with Google, later with a phone, and ends up with two profiles.
- Forcing login before the user has seen any value.