Node.js › Authentication & Authorization
How do you implement email verification and password-reset flows securely in a Node.js application?
IntermediateAnswer
Both flows rely on generating a cryptographically random, single-use token, storing only its hash in the database alongside an expiration timestamp, and emailing the user a link containing the raw token -- when the link is clicked, the submitted token is hashed and compared against the stored hash, and the action (verifying the email, or allowing a password reset) is only permitted if the hash matches and the token hasn't expired or already been used, after which the token is immediately invalidated to prevent reuse.
const crypto = require('node:crypto');
async function generateResetToken(userId) {
const rawToken = crypto.randomBytes(32).toString('hex');
const hashedToken = crypto.createHash('sha256').update(rawToken).digest('hex');
await db.passwordResets.create({ userId, hashedToken, expiresAt: Date.now() + 3600000 });
return rawToken; // only the raw token is emailed, never stored
}Real-world example A SaaS product's password-reset emails contain a link with a raw random token that expires after one hour and can only be used once; even if the reset-tokens database table were compromised, an attacker would only see hashed tokens that can't be reversed back into a working reset link.