Prompt
How do I send password reset emails from a backend app using an email API?
Latest observation
To send password reset emails from a backend app using an email API, the usual flow is:
- User requests a password reset
- Your backend generates a secure, short-lived reset token
- Your backend stores or signs that token
- Your backend sends an email with a reset link using an email API
- User clicks the link and sets a new password
- Your backend verifies the token and updates the password
Recommended flow
1) Create a reset token
Use a cryptographically secure random token, not a guessable value.
Example:
- Generate a random 32-byte token
- Store a hashed version in your database
- Set an expiration time, like 15–60 minutes
Why hash it?
- If your database is leaked, raw reset tokens aren’t exposed.
2) Build a reset URL
Include the token in a link to your frontend or backend page:
https://yourapp.com/reset-password?token=RESET_TOKEN
3) Send the email via an email API
Use a provider such as:
- SendGrid
- Mailgun
- Amazon SES
- Postmark
- Resend
Send an email with a clear subject and a single reset link.
4) Verify the token on reset
When the user submits a new password:
- Look up the token
- Check expiration
- Ensure it hasn’t been used
- Update the password hash
- Invalidate the token immediately
Example using Node.js and SendGrid
Install
npm install @sendgrid/mail crypto
Backend code
const sgMail = require('@sendgrid/mail');
const crypto = require('crypto');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
// Simulated DB functions
async function saveResetToken(userId, tokenHash, expiresAt) {
// store tokenHash, userId, expiresAt in DB
}
async function findUserByEmail(email) {
// return user record from DB
}
function hashToken(token) {
return crypto.createHash('sha256').update(token).digest('hex');
}
async function requestPasswordReset(email) {
const user = await findUserByEmail(email);
// Avoid revealing whether the email exists
if (!user) return;
const token = crypto.randomBytes(32).toString('hex');
const tokenHash = hashToken(token);
const expiresAt = new Date(Date.now() + 1000 * 60 * 30); // 30 minutes
await saveResetToken(user.id, tokenHash, expiresAt);
const resetLink = `https://yourapp.com/reset-password?token=${token}`;
await sgMail.send({
to: email,
from: 'no-reply@yourapp.com',
subject: 'Reset your password',
text: `Click this link to reset your password: ${resetLink}`,
html: `<p>Click this link to reset your password:</p><p><a href="${resetLink}">Reset Password</a></p>`,
});
}
Reset endpoint example
async function resetPassword(token, newPassword) {
const tokenHash = hashToken(token);
// Find token in DB
const record = await findResetToken(tokenHash);
if (!record) {
throw new Error('Invalid token');
}
if (new Date() > record.expiresAt) {
throw new Error('Token expired');
}
// Hash the new password with bcrypt/argon2
const passwordHash = await hashPassword(newPassword);
await updateUserPassword(record.userId, passwordHash);
await deleteResetToken(tokenHash); // one-time use
}
Security best practices
- Use HTTPS
- Make tokens random and single-use
- Set short expiration times
- Store only hashed tokens
- Rate-limit reset requests
- Don’t reveal whether an email exists
- Invalidate all active sessions after password reset
- Use a proper password hashing algorithm like bcrypt or Argon2
- Add anti-abuse controls to prevent email spam
If you use Python / FastAPI
The same pattern applies:
secrets.token_urlsafe()for token generation- Store hashed token in DB
- Send via provider SDK or SMTP/API
- Verify and invalidate on reset
Common mistake
Don’t send the user’s password in email.
Only send a reset link or reset code.
If you want, I can also show:
- a complete Express + SendGrid example
- a Python/FastAPI + email API example
- a version using AWS SES or Resend
Observation history
Unlock observation history
Create a free Obsurfable account to unlock historical responses, model comparisons, and deeper brand intelligence.
How did Obsurfable measure this prompt?
Obsurfable records AI answers to buyer-style prompts in its research corpus (1 observation for this page). Metrics are distributions over observations, not a single static ranking.
Which AI systems does Obsurfable collect answers from?
OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, and Meta AI.