Inbox
Back to Developers & QA

Password-reset QA · an account-recovery fire drill

Run the Recovery Fire Drill: How to Test Password Reset Before a Locked-Out User Has To

Test password reset end to end: request privacy, reset email and link, expiry, one-time use, repeated requests, password policy, old credentials, existing sessions, and final recovery.

Password reset is the emergency exit of authentication. Most users ignore it until their normal credential no longer gets them in, which is why a polished reset email is weak evidence. A useful test starts before the request, follows the recovery credential through the inbox, changes the password, and then stays for the aftermath: can the old password still log in, can the same reset action be accepted twice, how does a newer request affect an older one, and what happens to sessions that existed before recovery?

Quick answer: how do you test a password reset flow end to end?

Begin with a dedicated test account whose old password and active-session state are known. Request recovery through the public forgot-password form, match the resulting email to that request, inspect and use the intended reset link, set a valid new password, then prove the new password works and the old one does not. After the happy path, test unknown-account privacy, expiry, repeated use, repeated reset requests, and existing-session behavior as separate recovery cases.

Before pulling the alarm, write down the account state

BaselineRecord before resetWhy you need it later
CredentialA known old password for the dedicated test accountLets you prove the reset actually replaced the credential
Recovery addressThe exact inbox controlled by the testSeparates this recovery attempt from another identity
Account stateThe starting state required by your productPrevents another account-state defect from masquerading as reset failure
Session AA signed-in session created before recoveryLets you test what existing sessions do after password change
EnvironmentThe authorized staging or test targetLets you detect a reset URL that crosses environments

Question 1 — should “forgot password” reveal whether an email has an account?

This is one of the most useful negative cases because it happens before any email arrives. In an authorized test environment, submit the reset form once with a known test account and once with an unregistered test address. Compare the public behavior your product intends to keep consistent, including the user-facing message and response shape.

OWASP recommends a consistent message for existent and non-existent accounts and consistent response timing, alongside protections against excessive automated reset submissions. QA should therefore test the public request boundary, not merely assert that the known account eventually receives mail.

The recovery drill — walk one valid request all the way home

  1. 1

    Request one reset and timestamp the attempt

    Trigger recovery once for the dedicated account. Keep the request boundary clean before introducing another request.

  2. 2

    Match the reset email to that request

    Check recipient, sender, subject, arrival window, and environment. Do not select a link merely because it is the newest reset-looking message in a reused mailbox.

  3. 3

    Inspect the link without publishing the credential

    Confirm HTTPS, expected host, and reset route. Preserve sanitized diagnostics instead of copying a still-valid full token into long-lived logs or tickets.

  4. 4

    Open the public reset flow and choose a valid new password

    Exercise the user-facing recovery path and apply the same password policy the application promises elsewhere.

  5. 5

    Prove the credential transition

    After success, authenticate with the new password and separately prove the old password no longer authenticates the account.

  6. 6

    Inspect the aftermath

    Return to the session created before recovery, check any security notification the product promises, and verify the post-reset session policy explicitly.

Question 2 — what should happen when a password-reset link expires?

MomentAssertionDo not confuse it with
Inside validity windowA current valid reset action can reach the password-change stepEmail copy merely claiming the link is valid
After server-side expiryThe reset action cannot change the passwordA frontend countdown reaching zero
Expired-link screenThe user gets a safe route to request recovery againA generic server error that happens to block the reset
After rejectionAccount credential and protected state remain unchangedAssuming rejection text proves no state mutation occurred

Test the expiry boundary, not just the countdown

Expiry belongs to the server-side recovery contract. In a controlled test environment, prefer a supported way to shorten the reset lifetime or control test time rather than adding a long real-time wait to CI. The assertion is simple: a recovery action valid before the boundary must be rejected after the configured boundary without changing the account.

Keep the UI in the test when it communicates expiry. A technically correct rejection that strands a locked-out user with no way to request a fresh email is still a recovery defect.

Question 3 — can a password-reset link be used twice?

AttemptWhat to doWhat it proves
First useUse the valid link and set password BThe current recovery credential can complete its intended transition
Second useOpen the same reset action again after successWhether a consumed recovery credential follows the one-time-use policy
Credential checkTry password B and the previous password separatelyWhich credential owns the account after recovery
State checkConfirm the second use did not produce another password changeA rejected-looking page did not hide an unexpected mutation

OWASP's reset-token guidance maps directly to QA

OWASP recommends reset tokens or codes that are random, sufficiently long, securely stored, single use, and expired after an appropriate period. It also recommends that the account not be changed until a valid token is presented. Those properties become expiry, second-use, invalid-input, and no-premature-state-change tests.

Question 4 — should an old reset link work after requesting a new one?

Do not answer this from habit. Create reset request A and keep its link unused, then create request B. Test A and B deliberately and compare the results with the product's documented supersession policy. QA should prove the chosen policy is explicit and deterministic rather than borrowing a rule from another system.

This scenario also catches an inbox-testing trap: message B can arrive before message A. Delivery order does not tell you which reset request is newer. Keep request timestamps or another safe correlation boundary so the test knows which recovery action it is exercising.

Question 5 — which forgot-password test cases belong beyond the link?

CaseWhat should be assertedBug it can reveal
Weak new passwordThe normal password policy is enforced during recoveryReset path bypasses credential policy
Mismatched confirmationNo password change occursClient and server validation disagree
Invalid reset actionSafe rejection with unchanged account stateRecovery validation defect
Account bindingA recovery action changes only its intended test accountIdentity association defect
Wrong environmentReset action stays within the intended environmentStaging email points to production or vice versa
Repeated reset requestsRequest controls follow documented product policyForgot-password endpoint creates uncontrolled notification noise
Security notificationNotification is sent when promised and contains no live reset secretRecovery event happens silently or exposes sensitive material

Question 6 — what happens to existing sessions after a password reset?

This question needs a session created before the reset. If you test only in the same browser that performs recovery, navigation during the reset can destroy the evidence you needed. Keep a separate pre-reset session and revisit it after the password changes.

OWASP recommends either offering the user a way to invalidate existing sessions or invalidating them automatically. Your product may choose a specific policy, but QA should make that choice visible: does the pre-reset session remain authenticated, get revoked immediately, or require another event? Record the expected behavior and test it instead of assuming password change automatically means session revocation.

OWASP also advises against automatically logging the user in after reset because doing so adds authentication and session-handling complexity. If a product intentionally chooses different behavior, that transition deserves its own explicit security review and test.

When recovery fails, locate the broken stage before filing the bug

SymptomInspect firstUseful evidence
Form says success but no mail arrivesRequest handling, outbound mail, routingAccount fixture, request time, environment
Mail arrives with wrong hostReset URL generation and environment configSanitized hostname and route
Link opens but password cannot be savedRecovery validation, password policy, reset stateValidation response and account state
New password works and old password also worksCredential update or authentication data sourceSeparate login results after reset
Same link is accepted againOne-time-use handlingFirst-use and second-use results
Reset succeeds but old session survives unexpectedlySession policy and session storeIndependent pre-reset session result
Known and unknown accounts respond differentlyForgot-password request privacySanitized response comparison

Release gate: evidence a password-reset test should leave behind

  • Known starting account, old credential, recovery address, environment, and an independent pre-reset session.
  • Known-account and unknown-account request behavior compared according to account-privacy policy.
  • Reset message tied to the intended request with sender, recipient, subject, and arrival window.
  • HTTPS host and route verified without needlessly persisting the live reset credential.
  • Valid reset completes only after valid recovery credential presentation.
  • New password authenticates and old password no longer does.
  • Expired, repeated-use, invalid, and repeated-request cases follow documented policy.
  • Existing-session behavior after reset is explicitly asserted.
  • Recovery or security notification is checked when the product promises one.

A password-reset test should feel less like checking an email template and more like rehearsing an emergency. Start with a known account, prove the request protects account privacy, use the recovery credential once, replace the password, then inspect everything the reset leaves behind. The flow is healthy only when the right user can recover the right account and earlier credentials, recovery actions, and sessions behave exactly as the product's security policy says they should.

Need a clean recipient for manual email QA?

Use MailOnce to inspect real signup, OTP, magic-link, password-reset, and notification messages without putting a personal inbox into the test fixture.

Create temporary email

Sources & further reading

Primary security and test-runner documentation used to ground the testing guidance.

Continue testing

Move to the next boundary in the same email-testing problem space.