पाठ 6 / 25
Password Reset and Email Verification
Single-use, expiring, unguessable tokens.
Building a safe reset flow
Generate a cryptographically random token (at least 128 bits), store only its hash with the user ID and a short expiry, and email a link containing the raw token. When the link is used: look up by hash, check expiry, let the user set a new password, then delete the token (single use) and invalidate existing sessions. Always respond "If an account exists, we sent an email" to avoid enumeration. Build the link from a configured base URL, not the request Host header, which attackers can poison. Email verification works the same way: a random, expiring, single-use token proving control of the address. Never auto-login a user from a reset link without care, and never send passwords by email.
Issuing and redeeming a reset token
Node.js crypto; only the SHA-256 of the token is stored.
import crypto from 'node:crypto';
const sha256 = (s: string) => crypto.createHash('sha256').update(s).digest('hex');
export async function requestReset(email: string) {
const user = await db.users.findByEmail(email);
if (user) {
const token = crypto.randomBytes(32).toString('base64url'); // 256 bits
await db.resetTokens.insert({
userId: user.id,
tokenHash: sha256(token),
expiresAt: new Date(Date.now() + 30 * 60 * 1000), // 30 minutes
});
await mailer.send(user.email, `${APP_BASE_URL}/reset?token=${token}`);
}
// same response whether or not the account exists
return { message: 'If an account exists for that email, we sent a reset link.' };
}
export async function redeemReset(token: string, newPassword: string) {
const row = await db.resetTokens.findByHash(sha256(token));
if (!row || row.expiresAt < new Date()) throw new Error('invalid or expired link');
await db.users.setPasswordHash(row.userId, await hashPassword(newPassword));
await db.resetTokens.deleteAllForUser(row.userId); // single use
await sessions.revokeAllForUser(row.userId); // log out other devices
}Why store a hash of the token?
Reset tokens are password-equivalent until they expire. Hashing them means a database leak or a read-only SQL injection does not hand attackers working reset links. A fast hash is fine here because the token is long and random.
त्वरित जाँच: Which property should a password reset token NOT have?
- Only its hash is stored server-side
- It is generated with a cryptographically secure random source
- It expires after a short time
- It stays valid after it has been used once
Answer
It stays valid after it has been used once — Reset tokens must be single use and short-lived.