Prompt
How do I send password reset emails from an API?
Latest observation
To send password reset emails from an API, the usual flow is:
- User submits their email address
- Your backend verifies the account exists
- Backend generates a secure, single-use reset token
- Backend stores a hashed version of that token with an expiration time
- Backend sends an email containing a reset link with the token
- User clicks the link and sets a new password
- Backend verifies token, updates password, and invalidates the token
Typical API endpoints
1) Request a reset email
POST /auth/password-reset-request
Body
{
"email": "user@example.com"
}
Behavior
- Always return a generic success response like:
{
"message": "If an account exists, a reset email has been sent."
}
- This avoids revealing whether the email is registered
2) Confirm reset with token
POST /auth/password-reset-confirm
Body
{
"token": "reset-token-from-email",
"newPassword": "NewStrongPassword123!"
}
Behavior
- Validate token
- Check expiration
- Hash and store the new password
- Invalidate the token after use
How to generate the token
Use a cryptographically secure random token, for example:
- 32 bytes random
- URL-safe encoded
Example conceptually:
- generate token
- store
hash(token)in DB - email the raw token in a link
Why hash it?
If your database is compromised, attackers shouldn’t be able to use raw reset tokens.
Example email link
https://yourapp.com/reset-password?token=abc123...
Or if you use a frontend app:
https://app.yourdomain.com/reset-password?token=abc123...
Important security practices
- Do not send the new password by email
- Do not include sensitive user info in the email
- Use HTTPS only
- Make tokens:
- random
- single-use
- short-lived, e.g. 15–60 minutes
- Rate-limit reset requests
- Return the same response whether or not the email exists
- Invalidate all existing sessions after password reset if appropriate
- Consider logging password reset events for auditing
Example implementation outline
Request handler
// POST /auth/password-reset-request
const token = crypto.randomBytes(32).toString("hex");
const tokenHash = sha256(token);
saveResetTokenToDB(user.id, tokenHash, Date.now() + 3600000); // 1 hour
sendEmail(user.email, `
Click here to reset your password:
https://yourapp.com/reset-password?token=${token}
`);
Confirm handler
// POST /auth/password-reset-confirm
const tokenHash = sha256(req.body.token);
const record = findResetToken(tokenHash);
if (!record || record.expiresAt < Date.now()) {
return res.status(400).json({ message: "Invalid or expired token" });
}
const passwordHash = hashPassword(req.body.newPassword);
updateUserPassword(record.userId, passwordHash);
deleteResetToken(record.id); // single-use
If you’re using an email service
You can send the email through:
- SendGrid
- Mailgun
- Amazon SES
- Postmark
- Resend
- Nodemailer with SMTP
If you want, I can also give you:
- a Node.js/Express example
- a Python/FastAPI example
- a Laravel example
- or a database schema for reset tokens
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.