Skip to content
Bugwise
Menu
Features & Flows

Password Reset

How "Forgot password?" works, from the request to the email link to the new password, what usually breaks, and how to test reset links, expiry, emails and sessions on mobile and web.

30 min beginner Mobile & web

Everyone forgets a password sooner or later: the gym app you haven’t opened since January, the airline account you use twice a year. So they tap Forgot password?, wait for an email and choose a new password. When that works, nobody notices. When it doesn’t, the customer is locked out of their own account, and support gets the call.

Password reset is also a back door into the account. Whoever controls the reset link controls the account, no old password needed. That makes it one of the most security-sensitive flows a beginner tester will touch. The good news: most reset bugs are found by simple, careful observation, and you’ll find six of them yourself in this lesson.

How it works

  1. 1 · App

    User taps "Forgot password?" and enters an email

  2. 2 · App

    Same confirmation for every email: "If an account exists, we sent a link"

  3. 3 · Email

    Link with a long random token, valid once and for a short time

  4. 4 · App

    Link opens the reset screen, user sets a new password (same rules as sign up)

  5. 5 · Server

    Password saved, token burned, other sessions signed out, "password changed" email sent

Life of a reset token

Valid · just issued, unused, not expired

becomes invalid forever when it is…

  • Used · Password was changed with it
  • Expired · Older than the limit (e.g. 30 min)
  • Replaced · A newer link was requested (if the spec says so)
A reset link is a temporary key to the account. Most reset bugs are a key that keeps working when it shouldn't.
  1. The user asks for a reset. They tap Forgot password? and enter their email (sometimes a phone number).
  2. The app shows the same confirmation for everyone. Something like “If an account exists for this email, we’ve sent a link.” It must not say whether the email is registered. Otherwise the reset form becomes a tool for account enumerationAccount enumerationFinding out which emails are registered from differences in error messages or responses.Open in glossary →.
  3. The server creates a token and emails a link. The token is a long random string, stored on the server with an expiry time (often 15 to 60 minutes) and a used flag. The link looks like https://app.example.com/reset?t=8f2a….
  4. The user opens the link. On a phone, a deep linkDeep linkA link that opens a specific screen inside an app instead of just its home screen.Open in glossary → should open the app’s reset screen. If the app isn’t installed, the website opens instead.
  5. The user sets a new password. The same rules as at sign up apply (for example “at least 8 characters”). Some products also refuse the current password, or recently used ones.
  6. The server finishes the job. It saves the new password (as a hash, see password hashingPassword hashingStoring a one-way scrambled version of a password instead of the password itself.Open in glossary →), marks the token as used, signs out other sessions if the spec says so, and sends a “Your password was changed” email so the real owner notices if it wasn’t them.

Users impatiently tap Send reset link three times, then open the first email. What should happen? There are two common designs:

DesignWhat happensWhy teams choose it
Only the latest link worksRequesting a new link cancels all older onesFewer valid keys to the account at the same time. A common choice.
All unexpired links workAny link works until it is used or expires; using one cancels the restFriendlier when emails arrive out of order

Neither is “the” right answer. What matters is that the behavior matches the spec, and that a link never keeps working after a password was successfully changed. If the spec doesn’t say, ask. That question alone often uncovers a missing requirement.

Example requirements

Criterion 7 is rate limitingRate limitingCapping how many requests a user or device can make in a period of time.Open in glossary →: without it, anyone could flood a person’s inbox with reset emails, or hammer the server to test thousands of emails.

What a good reset email looks like

The email is part of the feature, so test it like a screen. Open it, read every word, and check where the link points.

Leaks and wrong environment

FreshCart

Your password

Hi {{first_name}},

You asked for your password. It is: Secret123! You can change it here:

Reset password

http://test-env.freshcart.local/reset?email=anna@test.com

A broken name placeholder, the actual password in plain text (which also suggests the server stores it unhashed), a link to a test environment over plain http, and the email address in the URL.

Safe and clear

FreshCart

Reset your FreshCart password

Hi Anna,

Tap the button to choose a new password. The link expires in 30 minutes and works once.

Reset password

https://freshcart.com/reset?t=8f2a…

Didn't ask for this? Ignore this email. Your password won't change.

Real name, a clear call to action, the expiry time, a random token in an https link to the production domain, and a line for people who didn’t ask for it.

What usually goes wrong

#BugWhat you seeTypical severity
1Account enumeration“No account with this email” for unknown emails, “Link sent” for real onesMedium–High (security)
2Link never expiresA link from yesterday (or last month) still opens the reset screenHigh (security)
3Link works twiceAfter resetting, the same link lets you set another passwordHigh (security)
4Old links stay validYou requested three links and all three work, although the spec says only the latestMedium–High
5Password in the email“Your password is …” in the email, or the new password repeated in the confirmationCritical (security)
6Wrong environment in the linkLink points to staging. or localhost, or to the website instead of opening the appHigh
7Other sessions surviveAfter the reset, the old phone or a stolen laptop is still logged inHigh (security)
8Password rules not enforcedThe reset screen accepts abcd although sign up requires 8 charactersMedium–High
9No rate limitYou can trigger 100 reset emails in a minuteMedium (security, cost)
10Email problemsEmail never arrives, lands in spam, wrong name or language, broken on mobile mail appsMedium
11Deep link problemsLink opens the browser, opens the app’s home screen and loses the token, or crashes when the app was closedMedium–High
12Old password still worksAfter a successful reset, both the old and the new password log inCritical

Find the bug

PulseFit’s reset flow below has six bugs. Under the phone you have a real-feeling inbox, a server clock you can move forward, and a list of Maya’s other devices. Explore like a tester:

  • Request a reset for Maya’s email, then for an email that doesn’t exist. Compare the messages.
  • Request several links. Open the older one.
  • Move the clock forward, then open a link.
  • Read every email carefully, including the small print.
  • Reset the password and look at the other devices. Try a very short password too.

🐞 Bug hunt: PulseFit password reset

This demo has 6 hidden bugs. Explore it like a tester, then check your findings.

Found0/6
9:41

PulseFit

Train smarter every day

Server clock

09:41

Inbox · maya@test.com

No emails yet.

    Maya's other devices

    • Maya's iPadPulseFit appSigned in
    • Chrome on Macpulsefit.comSigned in

    Test account & spec

    maya@test.com / Morning5k!

    • Messages must not reveal whether an email is registered.
    • A link expires after 30 minutes and works once. Requesting a new link cancels older ones.
    • Links point to app.pulsefit.com.
    • New password: at least 8 characters, different from the current one.
    • A reset signs the user out on all other devices.
    • Max 5 reset requests per 15 minutes.
    1. 1

      Hint: Request a link for maya@test.com, then for nobody@test.com.

    2. 2

      Hint: Send two reset links, then open the older email.

    3. 3

      Hint: Request a link, tap "+1 hour" on the server clock, then open it.

    4. 4

      Hint: Read the full reset email, including the small "Or open this link" line.

    5. 5

      Hint: Complete a reset, then look at "Maya's other devices".

    6. 6

      Hint: Set the new password to "abcd".

    Test scenarios

    Functional

    • Request a reset for a registered email, receive the email, open the link, set a valid new password.
    • Log in with the new password: works. Log in with the old password: rejected.
    • A “Your password was changed” email arrives after the reset.
    • The email address is trimmed and case-insensitive: Maya@Test.com works for maya@test.com.
    • The reset screen shows which account it’s for (or at least doesn’t let you change someone else’s).
    • The back and cancel paths work: leaving the reset screen without saving keeps the old password.

    Negative

    • Unknown email: same message, same timing, no email sent. Also check the response in DevToolsDevToolsDeveloper tools built into browsers for inspecting pages, network traffic and errors.Open in glossary → or a proxy: the status code and body should look the same too.
    • Badly formatted email: maya@, maya.test.com, empty field.
    • Expired link: wait (or ask a developer to shorten the expiry on a test environment), then open it.
    • Used link: reset once, then open the same link again.
    • Older link after requesting a newer one: does it work? Compare with the spec.
    • Tampered link: change one character of the token in the URL. It must fail with a friendly message, not a crash or a 500.
    • New password that breaks the rules, confirmation that doesn’t match, new password equal to the current one (if required).

    Edge cases

    • Expiry boundaries: with a 30-minute limit, try at about 29 and 31 minutes. That’s boundary value analysisBoundary value analysisTesting values at and just around the edges of valid ranges, where bugs love to hide.Open in glossary → applied to time.
    • Password length boundaries: 7, 8 and 9 characters, the maximum and one more.
    • Request a reset while logged in on another device, then use the link.
    • Two resets in parallel: open link A in one browser tab and link B in another, submit both.
    • The password is changed via Settings (not reset) while a reset link is pending: does the link still work? It usually shouldn’t.
    • The account is locked after too many login attempts: does a successful reset unlock it? Check the spec.
    • Social login accounts (Sign in with Apple/Google) that have no password: what does reset do for them?
    • Unicode and special characters in the new password; a password set on the web must also work in the app.

    UI & usability

    Security basics

    These are defensive checks you can do with no special skills:

    Accessibility

    Example test cases

    TC-RESET-001Reset password with a valid link

    Preconditions

    • Account maya@test.com exists
    • User is logged out

    Steps

    1. Tap "Forgot password?"
    2. Enter maya@test.com and tap "Send reset link"
    3. Open the email and tap "Reset password"
    4. Enter a valid new password twice and save
    5. Log in with the new password
    6. Log out and try the old password

    Test data

    new password: Sunrise2026!

    Expected result

    Reset screen opens in the app. The new password logs in. The old password is rejected. A "password changed" email arrives.

    TC-RESET-002Same message for registered and unknown emails

    Steps

    1. Request a reset for maya@test.com
    2. Note the message
    3. Request a reset for nobody@test.com
    4. Compare messages, status codes and response times

    Expected result

    Both show exactly "If an account exists for this email, we've sent a link to reset your password." Only maya@test.com receives an email.

    TC-RESET-003Link expires after 30 minutes

    Preconditions

    • Test environment with a controllable clock, or a reset email that is 31 minutes old

    Steps

    1. Request a reset link
    2. Open it after 29 minutes (expect it to work, then cancel)
    3. Open a fresh link after 31 minutes

    Expected result

    At 29 minutes the reset screen opens. At 31 minutes the app shows "This link has expired" with a button to request a new one.

    TC-RESET-004Link cannot be used twice

    Steps

    1. Complete a reset with a link
    2. Open the same link again

    Expected result

    The app shows "This link has already been used". The password cannot be changed.

    TC-RESET-005Requesting a new link cancels older links

    Steps

    1. Request link A
    2. Request link B
    3. Open link A

    Expected result

    Link A shows "This link can't be used". Link B works.

    TC-RESET-006Reset signs out other devices

    Preconditions

    • Maya is logged in on an iPad and in a desktop browser

    Steps

    1. Reset the password on the phone
    2. Use the app on the iPad
    3. Reload the page in the desktop browser

    Expected result

    Both the iPad and the browser ask Maya to log in again.

    TC-RESET-007Reset email content

    Preconditions

    • Account language is German

    Steps

    1. Request a reset
    2. Open the email on a phone and on desktop
    3. Long-press or hover over the button to see the URL

    Expected result

    Email is in German, greets the user by name, contains no password, shows the expiry time, and the link uses https://app.pulsefit.com.

    Tip: click a test case to expand it.

    Mobile vs web

    • Deep links: tap the link in the Mail app and in Gmail. With the app installed it should open the app’s reset screen (iOS Universal Links, Android App Links; see Deep links). Test with the app not installed, closed, in the background, and logged in as someone else. See Interruptions for switching between apps.
    • In-app browsers: Gmail and Outlook may open links in their own browser instead of your app. The website fallback must work there too.
    • Read the email on the same phone: switching from the app to the mail app and back must not lose what the user typed.
    • Password managers: after the reset, iOS Passwords or Google Password Manager should offer to update the saved password.
    • Biometrics: if Face ID or fingerprint unlocks a saved password, it must not keep logging in with the old one after a reset.
    • Other devices: keep a second phone or tablet logged in and check it gets signed out.
    • Open the link in a different browser than the one that requested it, and in a private window. It should still work (the token is in the link, not in a cookie).
    • Network tab: in DevToolsDevToolsDeveloper tools built into browsers for inspecting pages, network traffic and errors.Open in glossary →, check the reset request is a POST, the response doesn’t reveal whether the email exists, and the token never appears in third-party requests (analytics, ads).
    • Back button: after a successful reset, pressing Back must not let you submit the form again.
    • Other tabs: a second tab logged in as the same user should be signed out after the reset (if specified).
    • Email preview: desktop mail clients and webmail render HTML differently. Check the button and the plain link both work.
    • Cross-browser: the reset page works in Chrome, Safari and Firefox, including autofill of the new password.

    Checklist

    Password reset checklist

    0 of 15 checked

    Check your understanding

    Quick quiz

    0/5 answered · 0 correct

    1. 1.Which confirmation message is safest after "Send reset link"?

    2. 2.The spec says reset links expire after 30 minutes. Which test best checks this?

    3. 3.You requested two reset links. The older one still works. Is it a bug?

    4. 4.The reset email says: "Your current password is Morning5k!". What does this tell you?

    5. 5.Maya resets her password because her laptop was stolen. What must happen to the laptop session?

    Key takeaways

    • A reset link is a temporary key to the account: it must be random, expire, work once, and older links must behave exactly as the spec says.
    • Show the same message for every email, so the reset form can’t be used to find out who has an account.
    • Test the email like a screen: no passwords, right name and language, and a link to the right environment.
    • After a reset: the new password works, the old one doesn’t, other sessions are signed out, and a “password changed” email arrives.
    • On mobile, check deep links with the app installed, closed and missing; on the web, check other tabs and the Network panel.

    Finished this page?Nice work, this page is complete!

    Mark it as done to track your progress. It's saved in this browser, no account needed.

    Its review cards are now in Bites ⚡
    Esc

    Type to search the whole site.