Skip to main content

Request Password Reset

Sends a password reset link to the user's email address. Use this when users forget their password.

Endpoint​

POST /api/v1/auth/password-reset

Authentication​

No authentication required (public endpoint).

Request​

Content-Type​

application/json

Request Body​

FieldTypeRequiredDescription
emailstringYesEmail address to send reset link to

Example Request​

{
"email": "john@example.com"
}

Response​

Success Response (200 OK)​

{
"message": "If the email exists, a password reset link has been sent",
"success": true
}
Security Note

The endpoint always returns success, even if the email doesn't exist. This prevents attackers from discovering which emails are registered.

Examples​

curl -X POST https://api.callcov.com/api/v1/auth/password-reset \
-H "Content-Type: application/json" \
-d '{
"email": "john@example.com"
}'

Password Reset Flow​

  1. User requests reset β†’ This endpoint
  2. Backend sends email β†’ Email with reset link and token
  3. User clicks link β†’ Redirected to frontend with token
  4. User enters new password β†’ Frontend calls /auth/password-reset/confirm
  5. Password updated β†’ User can log in with new password

Email Content​

Users receive an email containing:

  • Password reset link with token
  • Link expires in 15 minutes
  • Token is single-use

Example email:

Subject: Reset your CallCov password

Click the link below to reset your password:
https://app.callcov.com/reset-password-confirmation?token=abc123...

This link expires in 15 minutes.

If you didn't request this, you can safely ignore this email.

Frontend Integration​

Typical "Forgot Password" form:

async function handleForgotPassword(email) {
try {
const response = await fetch('https://api.callcov.com/api/v1/auth/password-reset', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email })
});

if (response.ok) {
// Show success message
alert('If your email is registered, you will receive a password reset link.');
}
} catch (error) {
console.error('Error:', error);
alert('Something went wrong. Please try again.');
}
}

Rate Limiting​

To prevent abuse:

  • Maximum 3 requests per email per hour
  • Maximum 10 requests per IP per hour

Security Behavior​

When this endpoint is called:

  1. Invalidates all previous reset tokens for this user
  2. Generates new reset token (expires in 15 minutes)
  3. Sends reset email
  4. Always returns success (even if email doesn't exist)

Security Considerations​

  • Email enumeration protection: Always returns success
  • Token invalidation: Previous reset tokens are invalidated
  • Time-limited: Tokens expire in 15 minutes
  • Single-use: Tokens can only be used once
  • Rate limited: Prevents email bombing

Testing in Development​

In development mode, reset emails are sent to MailHog (http://localhost:8025).

Common Issues​

Email Not Received​

Possible reasons:

  1. Email in spam folder
  2. Incorrect email address
  3. Email service temporary issue

Solution: Wait a few minutes, check spam, or try resending.

Rate Limit Exceeded​

{
"detail": "Too many password reset requests. Please try again later."
}

Solution: Wait an hour before trying again.

Complete Reset Form Example​

function ForgotPasswordForm() {
const [email, setEmail] = useState('');
const [sent, setSent] = useState(false);
const [loading, setLoading] = useState(false);

const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);

try {
await fetch('https://api.callcov.com/api/v1/auth/password-reset', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email })
});

setSent(true);
} catch (error) {
alert('Something went wrong. Please try again.');
} finally {
setLoading(false);
}
};

if (sent) {
return (
<div className="success-message">
<h2>Check your email</h2>
<p>
If your email is registered, you will receive a password reset link
shortly.
</p>
<p>
Didn't receive it? Check your spam folder or try again in a few
minutes.
</p>
</div>
);
}

return (
<form onSubmit={handleSubmit}>
<h2>Forgot Password?</h2>
<p>Enter your email and we'll send you a reset link.</p>

<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="your@email.com"
required
/>

<button type="submit" disabled={loading}>
{loading ? 'Sending...' : 'Send Reset Link'}
</button>

<a href="/login">Back to Login</a>
</form>
);
}