How to Test Password Reset Flow (Mobile and Web)
Password reset is where frustrated users go when locked out. If the flow is broken, users give up and churn. It is also a common attack vector. Security and usability must balance. This guide covers t
Password reset is where frustrated users go when locked out. If the flow is broken, users give up and churn. It is also a common attack vector. Security and usability must balance. This guide covers testing both dimensions.
What to test
Request reset
- "Forgot password" link visible on login
- Email input accepts valid email
- Invalid email format rejected inline
- Non-existent email — ambiguous response (do not leak account existence)
- Rate-limit applied (prevent abuse)
- Confirmation message generic ("If an account exists, email sent")
Reset email
- Email arrives within minutes
- Email comes from verified sender (SPF, DKIM)
- Reset link clearly identifies as password reset
- Link has expiration (visible or stated)
- Link is unique (not guessable)
- Link is single-use (second use invalid)
Reset page
- Link opens reset form
- Form shows email (confirmation) or not (privacy)
- New password field with complexity rules visible
- Confirm password field
- Submit enabled when valid
- Server-side validates rules (not trusting client)
- Success navigates to login or auto-login
Post-reset
- User can login with new password
- Old password no longer works
- Existing sessions invalidated (per security policy)
- Confirmation email sent
- Login notifications fire for unusual device
Security
- Reset link not reusable
- Reset link expires (typically 1-24 hours)
- Rate limit on reset requests per email / IP
- Email sent via authenticated channel (not spoofed)
- Account does not unlock on reset request (still locked until reset completed if account was locked)
- Password not logged / not in URL
- Reset does not reveal user existence to non-user
Edge cases
- User requests multiple resets — most recent link wins, older invalidated
- User clicks old link → expired, offer to request new
- Email arrives after user manually resolved (cached)
- Link opens in wrong app (WebView vs native)
- Reset while logged in on another device — session preserved or cleared per policy
- Email contains "Hey [Name]" — name rendered correctly across clients
- Reset attempted for soft-deleted account — rejected
Accessibility
- Email form labeled
- Reset form inputs labeled
- Error messages announced
- Keyboard navigable
- Links in email accessible when opened
Mobile-specific
- Email link opens the app (deep link) or browser fallback
- Reset form mobile-friendly layout
- Password paste enabled (respects password managers)
Web-specific
- Reset URL works across browsers
- CORS / CSRF protected
Manual testing
Use a dedicated test email for each reset cycle. Test:
- Valid email → receive → reset → login
- Expired link → graceful error
- Reused link → graceful error
- Non-existent email → generic response
- Very rapid repeated requests → rate-limited
- Email in spam → marked as legitimate / SPF correct
- Link on mobile vs desktop email clients
- Reset works for social-linked accounts (or clear message it does not)
Automated
Integration test (backend)
def test_reset_request_sends_email(api_client, mock_mailer):
api_client.post("/api/auth/request-reset", json={"email": "test@example.com"})
assert mock_mailer.sent_count == 1
assert "reset" in mock_mailer.last_email.subject.lower()
End-to-end (Playwright)
def test_reset_flow(page, mailbox):
# Request
page.goto("/login")
page.click("text=Forgot password?")
page.fill("#email", "test@example.com")
page.click("text=Send reset link")
# Fetch email from test mailbox
link = mailbox.get_latest_link("reset")
page.goto(link)
page.fill("#new-password", "NewStrongP@ss456")
page.fill("#confirm-password", "NewStrongP@ss456")
page.click("text=Reset password")
expect(page.locator("text=Password reset")).to_be_visible()
How SUSA handles reset
SUSA drives the reset request form. For full end-to-end (requires email interception), pair SUSA with a test mail capture like Mailtrap or a local SMTP sink.
The adversarial persona probes:
- Invalid email formats
- Rapid repeated requests (rate limit)
- Empty / malformed inputs
susatest-agent test myapp.apk --persona adversarial --steps 50 --flow password-reset
Common production bugs
- Reset link leaks user existence — 404 for nonexistent vs 200 for existent
- Rate limit absent — attacker spams reset emails as harassment
- Reset password allowed weak, login rejects it — server-side validation mismatch
- Link still works after password successfully changed — single-use not enforced
- Old sessions remain active — compromised session persists post-reset
Password reset is high-value, high-risk. Test thoroughly, secure properly.
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free