NEXINFINITY META · Blog
Mobile Apps

Phone-Number Login in a Mobile App: Seven Things That Break in the Real World

S. Veera Kumar 8 min read

Phone-number login, where the user types a number and then a code, is the most natural sign-in for an app in India and one of the easiest to get subtly wrong. The demo works. The failures appear in the hands of real users and App Store reviewers, who leave the app to read a message, retype a country code, or live in a country where your SMS cannot reach them. These are seven failures we hit shipping phone-number login in our own Flutter apps, in the order a user meets them, with the fix for each.

Key takeaways

  • Never truncate a phone field silently, and write test credentials in exactly the format the field expects.
  • Hold the in-flight OTP request in a process-lifetime holder so leaving the app to read the SMS does not lose it.
  • Once the credential check succeeds, the user is signed in; later lookups must never report a false failure and should default to the self-correcting route.
  • Give App Review a fixed test identity with no SMS, and sign in with it yourself on submission day, because it expires.
  • Share one sign-in package across your apps so each fix is made once.

1. The country code typed twice

Our sign-in screen shows the country code already selected, so the number field expects ten digits. Apple's reviewer read our review notes, saw the number written with the country code in front of it, and typed all twelve digits. The field silently kept the first ten, so the code was sent to a different number, and the screen then reported an invalid code. Apple rejected the app for that, and the attached screenshot, which showed the masked number the code had been sent to, is the only reason we understood it.

Two fixes, and you need both. Never truncate silently: a field that cannot hold what was typed should say so, or accept and normalise it. And write test credentials exactly as the field expects them, in the format it displays.

12 → 10
Digits typed versus digits the field silently kept
1 wrong number
Where the code actually went

2. Leaving the app to read the code

The user taps send, switches to their messages to read the code, and comes back. In our apps, coming back sent them to the first screen and discarded the half-entered code. The cause was routing: the router had stored the in-flight request as extra data on the route, and when the app resumed, a state change rebuilt the router from the saved route information, where that data had been silently dropped to nothing. With no request to show, the screen bounced to login.

The fix is to hold the in-flight request in a holder that lives for the life of the process, and read it from there when the route data is missing. Also do not emit lock or permission changes into the router while nobody is signed in; refreshing the router during the login window only churns it. The holder is cleared on success, on going back and on sign-out, because it holds a phone number.

3. The correct code that says it failed

Testers reported entering the right code, seeing verification failed, and then being taken into the app anyway. The sign-in had succeeded, the session was live, and the app then looked up whether this was a new or returning user. That lookup failed on a momentary network error and threw, and the whole call reported a generic failure, while the valid session carried on navigating.

Once the credential step succeeds, the user is signed in. Every later read is only a routing hint. Put each one in its own best-effort block that defaults to a safe route and returns success. A failure after the credential check must never be reported as a failure of the credential.

4. New or returning: choose the safe default

When the follow-up lookup does fail, the default matters. Defaulting to new user sends a returning customer to the profile-setup form, which will not bounce them off and can overwrite their existing name and handle. Defaulting to returning user sends a genuinely new user to the home screen, where the router's own check sees there is no profile and forwards them to setup. One default is self-correcting; the other strands people. Always choose the self-correcting one.

5. The reviewer cannot receive your SMS

App Review is done by people who are not in your country and who cannot receive a text on your numbers. An app with only SMS sign-in is simply unreviewable unless you provide a way in. The standard answer is a test identity on your authentication service: a fixed number with a fixed code, where no message is ever sent and the code always works. Say in the review notes that no SMS is sent and that the code is fixed.

Apple files a failed sign-in under Guideline 2.1, app completeness, and it is one of the most common reasons first submissions are rejected. We cover the full set of store rejections in what shipping two apps to both stores taught us.

6. The test identity that expired

Our test identity worked at first submission. By the next release it had a lapsed confirmation date on the authentication service, and the reviewer could not get in. Nobody had signed in with it since the previous review, so nobody knew. It was the second rejection of the same app for a demo-credential reason, which is the real lesson: the demo path is part of the product and rots like anything else.

Sign in with the test identity yourself, on a phone, using the exact text in the review notes, on the day you submit. It takes two minutes, and it is the cheapest item on any release checklist.

7. One login screen, many apps

All of our apps share one login, one-time-code and profile-setup package. That is why the failures above hit every app at once, and also why each fix reached every app at once: the resume fix, the false-failure fix and the no-silent-truncation fix were made once, in the package, and flowed into each app's next release. If you are building more than one app, a shared sign-in package is not over-engineering; it is the difference between fixing a bug once and fixing it five times.

FailureFix
Country code typed twice, silent truncationNever truncate silently; write credentials in the field's own format
Half-entered code lost when the app resumesHold the in-flight request in a process-lifetime holder
Correct code reports failureIsolate every post-success read; a late failure is not a credential failure
Returning user sent to setupDefault to returning; the router corrects new users
Reviewer cannot receive SMSA fixed test identity with no SMS sent, stated in the notes
Test identity lapsedSign in with it yourself on the day you submit
Same bug in every appOne shared sign-in package

The seven failures and the one-line fix for each

What to ask your developer

Before you commission phone-number login, ask five questions. What happens if the user leaves the app and returns mid-code? What does the user see if the code is right but the next lookup fails? How will App Review get in? Who checks the test identity on submission day? And can the same sign-in code be shared across your apps? If the answers are vague, the first rejection will answer them for you. Our mobile app development service treats sign-in and the store launch as named pieces of work, and what a mobile app costs in 2026 shows where they sit in a budget.

Frequently asked questions

Why does phone OTP login fail in App Store review?

Usually because the reviewer cannot receive your SMS or cannot use the credentials you gave. Provide a test phone number on your authentication service with a fixed code and no message sent, write it in the exact format the field expects, and sign in with it yourself on the day you submit. Apple files this under Guideline 2.1.

Why does my app lose the OTP screen when the user switches to read the SMS?

Often because the in-flight request was stored as extra data on the route, and a router rebuild on resume dropped it. Keep the request in a holder that lives for the process and read it as a fallback, and clear it on success, back and sign-out.

Why does a correct OTP show verification failed and then log the user in?

Because a lookup that runs after the credential check, such as profile or onboarding status, failed and was allowed to fail the whole call. Wrap every post-success read in best-effort handling that defaults to a safe route and still returns success.

Should a failed lookup default to new user or returning user?

Returning user. The home screen's own check will forward a genuinely new user to profile setup, whereas defaulting to new strands returning users on a form that can overwrite their existing profile.

What is a test phone number for app review?

A fixed phone number and fixed code configured on your authentication service so that no SMS is ever sent and the code always works. Mention in the review notes that no message is sent and the code is fixed.

Is a shared login package worth it for several apps?

Yes, once you have more than one app. The same sign-in bugs hit every app, and a shared package means each is fixed once and reaches every app in its next release.

Have a project in mind?

We design, build, and ship software end-to-end — with a fixed, written quote after a free scoping call.

More from the blog

Keep reading