CodeKits.devNew developer offer

Password Reset and Email Verification

A practical walkthrough of password reset and email verification, with code excerpts, failure checks and integration guidance.

By Jonathan · 5 min read

Published

Password Reset and Email Verification tutorial cover
In this article

This walkthrough covers Password Reset and Email Verification. An existing account system, a database supporting transactions, an email delivery adapter and a fixed trusted application URL. Use a local mail sink during development.

The video is an illustrated code walkthrough with AI narration. Code blocks are integration excerpts, not a complete tested application. Helper names such as stores, middleware and clients describe responsibilities you must implement in your existing project. No live server, payment provider or device execution is claimed.

Before you begin

Use a separate development environment, fictional data and test credentials. Record dependency versions and follow the official references below for your installed versions. Keep a working baseline and add one workflow at a time.

1. Separate the token purposes

Password reset and email verification have different effects, so model them as separate token purposes. Store only a digest of a high-entropy random token, together with its user, expiry, and use state. A verification token must not work as a reset token. Define the lifetime and revocation policy for each purpose, and remove stale records on a maintenance schedule.

Separate the token purposes
tokens:
 token_hash
 user_id
 purpose: reset | verify_email
 expires_at
 used_at

2. Avoid account discovery

Respond consistently whether or not an address belongs to an account. Avoid revealing account existence through status codes, text, or obvious timing differences. Apply per-account and network-level abuse controls without making account lockout a denial-of-service tool. Queue email work rather than exposing provider timing directly. Keep a support path for users who no longer control their email address.

Avoid account discovery
app.post("/api/reset-request", rateLimit, async (req,res) => {
 await queueResetIfAccountExists(normalizedEmail);
 res.json({message: "If eligible, an email will arrive."});
});

3. Build links from trusted configuration

Construct reset links from an allowlisted application URL in server configuration, not an untrusted host header. Persist the token's purpose and expiry before sending. Avoid recording raw tokens in logs or analytics. The destination page should avoid third-party content that could leak the URL, and use an appropriate referrer policy. Email delivery needs retries, but retries must not accidentally change the token's meaning.

Build links from trusted configuration
const raw = randomBytes(32).toString("hex");
const tokenHash = digest(raw);
const url = new URL("/reset-password", APP_BASE_URL);
url.searchParams.set("token", raw);
await tokenStore.create({tokenHash, userId, purpose: "reset"});

4. Consume the token atomically

Validate and consume the token in the same transaction as the password update. Lock the matching row or use an equivalent atomic conditional operation so two concurrent requests can't both succeed. Check purpose, expiry, and unused status. Store the new password using the account system's established hashing method. Revoke sessions according to policy and send a separate notification that the password changed.

Consume the token atomically
BEGIN;
SELECT * FROM recovery_tokens
 WHERE token_hash=? AND purpose="reset" FOR UPDATE;
-- Check unused and unexpired; update password hash.
-- Mark token used and revoke sessions.
COMMIT;

5. Keep verification scoped to the address

Email verification proves control of a particular address at a particular point in the workflow. Bind the token to the intended address as well as the account. If the address changes, invalidate earlier verification links or require an exact address match. Decide which features remain unavailable before verification. Don't automatically grant unrelated privileges just because an email link was opened.

Keep verification scoped to the address
verification = {userId, emailToVerify, tokenHash, expiresAt};
// On use: match the intended current email address.
// An old token must not verify a newly changed address.

6. Handle the React reset form

Collect the new password without displaying the raw token unnecessarily. Handle used, invalid, and expired links with a clear route to request another email. Don't automatically sign the user in unless that behaviour is deliberately designed and reviewed. After a successful reset, remove sensitive link data from the visible location where practical and guide the user through the normal sign-in flow.

Handle the React reset form
await fetch("/api/reset-password", {
 method: "POST",
 headers: {"Content-Type": "application/json"},
 body: JSON.stringify({token, password})
});
// Show one-use/expired link guidance and a new-request path.

7. Test email without real customers

Use a controlled mail sink for local development and inject an email adapter in automated tests. Assert the intended recipient and trusted link destination without contacting real customers. Test delivery failure separately from token consumption. In deployment, configure verified sending domains, provider credentials, retry policy, and monitoring. A unit test of token generation isn't proof that email delivery or inbox placement works.

Test email without real customers
Development: local mail sink
Tests: injected sendMail adapter
Check recipient, trusted URL and token purpose
Never print production credentials or reset tokens

Integration checks

Test unknown accounts, expired tokens, replay, wrong purpose, changed addresses, simultaneous submissions, delivery failure and session revocation after reset.

These are verification instructions, not reported test results. The excerpts have not been executed as a complete integrated application. Review authentication, database schema, dependency versions and operational settings before deployment.

Official references

Explore CodeKits development services.