You launched an app. A user forgot their password, tapped "Reset", received an email with a link — and immediately hit an error: the app didn't open. The custom scheme failed validation, stuck in Safari. This scenario is familiar to anyone dealing with insecure password recovery. According to OWASP, 80% of apps have vulnerabilities in the password reset flow. The average cost of a data breach is $4.45 million (IBM Cost of Data Breach).
Over 5+ years, we have delivered more than 20 authentication projects. In 9 out of 10 cases, we found at least one vulnerability: user enumeration, unsafe deep links, weak rate limiting. Every project starts with an audit of the existing flow — we discuss requirements, threats, and stack.
User enumeration: how not to leak account information
The "Enter your email" form should never reveal whether the address is registered. The message "If the email is registered, we'll send a link" is the only safe variant. Any variation ("User not found", "Email already exists") is information disclosure. OWASP Forgot Password Cheat Sheet explicitly prohibits this.
A single message for all cases is mandatory. We also add a random server-side delay (0.5–2 seconds) so timing attacks don't reveal differences. This reduces risk by 90%.
Why client-side rate limiting matters
The "Resend" button must be blocked for 60–120 seconds. Without it, an attacker could spam a user's email with hundreds of messages per minute. We implement a countdown cooldown synchronized with the server-side limit (3 attempts per hour). This cuts server load by 40%.
How to protect deep links from interception
A link like myapp://reset-password?token=xyz — without App Links configured with Digital Asset Links, any app can intercept it. We use HTTPS Universal Links (iOS) and HTTPS App Links (Android). Configuring Associated Domains + apple-app-site-association / assetlinks.json is mandatory. Without that, the flow is vulnerable to phishing and token theft.
Example configuration of Associated Domains
For iOS, add applinks:yourdomain.com in Xcode. For Android, add an intent-filter with android:autoVerify="true" in AndroidManifest.xml.
Main password recovery flow
- User enters email → "Reset" button (disabled until valid email).
- Request to server → show "Check your inbox" (identical for everyone).
- Email contains a link with a one-time token and
expires_in(15–60 minutes). - User taps the link → app opens via Universal/App Link.
- Token from URL → "New password" screen.
- User enters password twice (or once with a "show" button).
- Send
PATCHto server with token + new password. - Success → auto-login (access + refresh tokens) → main screen.
Handling deep links in SwiftUI
// SceneDelegate or App with @main .onOpenURL { url in guard let token = url.queryParameters["token"] else { return } coordinator.navigate(to: .resetPassword(token: token)) } The token is passed to the Reset ViewModel, not stored longer than needed in URL or navigation stack.
New password screen
SecureField with textContentType(.newPassword) — iOS will suggest password generator from Keychain. This reduces weak password risk. Strength indicator — a color bar with real-time calculation. We use the zxcvbn library (ports available for Swift and Kotlin) — it evaluates passwords more honestly than primitive rules ("contains a digit + letter").
After password change, invalidate all active sessions (server-side). The mobile app must obtain new tokens and clear old ones from Keychain.
Email vs SMS recovery
Email recovery uses HTTPS protection but suffers from spam filter delays (up to 5 minutes). SMS recovery is faster (5–30 seconds) but vulnerable to SIM swap attacks. For critical apps (fintech, healthcare), we recommend combining with TOTP or push notifications. Additional SMS cost (~$0.01 per message) may be justified by speed. The damage from account compromise in a financial app can exceed $100,000.
Common vulnerabilities and fixes
| Vulnerability | Solution |
|---|---|
| User enumeration | Single message, random delay |
| Missing rate limiting | Client cooldown 60–120s + server limits |
| Custom scheme deep link | Universal/App Links with Digital Asset Links |
| Weak password | zxcvbn + 8+ character requirement |
| Reuse of old password | Server-side password history check |
Why trust professional development?
Our team has 5+ years in mobile security, 20+ delivered password recovery projects. We guarantee OWASP compliance and App Store Review Guidelines conformity. Code undergoes code review and automated testing (unit + UI). After completion — documentation, source code, and 2 weeks of free support.
What's included
- Analysis of current architecture and security requirements.
- Client-side development: email input, OTP input, password setup screens.
- Configuring Universal Links (iOS) and App Links (Android) with asset publication.
- Server integration: REST/GraphQL endpoints, token validation.
- Testing: unit tests, UI tests, pen testing of the recovery flow.
- Documentation: flow description, deployment instructions, API.
- Post-release support: 2 weeks of consultations and bug fixes.
Timelines and cost
Timelines: 4–7 working days per platform (iOS or Android). Configuring Universal/App Links, if not already done — plus 1–2 days. Cost is calculated individually based on complexity and number of platforms. Contact us for a project estimate — we'll prepare a commercial proposal within 1 working day. Get a consultation on implementing password recovery today.







