Skip to main content

Confirm Password Reset

Completes the password reset process by setting a new password using the reset token from the email.

Endpoint​

POST /api/v1/auth/password-reset/confirm

Authentication​

No authentication required, but requires valid reset token.

Request​

Content-Type​

application/json

Request Body​

FieldTypeRequiredDescription
tokenstringYesReset token from email link
new_passwordstringYesNew password (see requirements below)

Password Requirements​

The new password must meet ALL of the following criteria:

  • Minimum 8 characters long
  • At least one uppercase letter (A-Z)
  • At least one lowercase letter (a-z)
  • At least one digit (0-9)
  • At least one special character (!@#$%^&*(),.?":|<>)

Example Request​

{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"new_password": "NewSecurePass123!"
}

Response​

Success Response (200 OK)​

{
"message": "Password reset successfully",
"success": true
}

After successful reset, the user can log in with their new password using the login endpoint.

Examples​

curl -X POST https://api.callcov.com/api/v1/auth/password-reset/confirm \
-H "Content-Type: application/json" \
-d '{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"new_password": "NewSecurePass123!"
}'

Frontend Integration​

Typical password reset confirmation flow:

// User clicks reset link: https://app.callcov.com/reset-password-confirmation?token=abc123...

function ResetPasswordForm() {
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [success, setSuccess] = useState(false);
const [error, setError] = useState('');

// Extract token from URL
const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get('token');

const handleSubmit = async (e) => {
e.preventDefault();
setError('');

// Validate passwords match
if (password !== confirmPassword) {
setError('Passwords do not match');
return;
}

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

if (response.ok) {
setSuccess(true);
// Redirect to login after 2 seconds
setTimeout(() => {
window.location.href = '/login';
}, 2000);
} else {
const data = await response.json();
setError(data.detail);
}
} catch (error) {
setError('Something went wrong. Please try again.');
}
};

if (success) {
return (
<div className="success-message">
<h2>βœ… Password Reset Successful!</h2>
<p>Redirecting to login...</p>
</div>
);
}

return (
<form onSubmit={handleSubmit}>
<h2>Set New Password</h2>

<input
type="password"
placeholder="New Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
minLength={8}
/>

<input
type="password"
placeholder="Confirm Password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
required
minLength={8}
/>

{error && <div className="error">{error}</div>}

<button type="submit">Reset Password</button>

<div className="password-requirements">
<p>Password must contain:</p>
<ul>
<li>At least 8 characters</li>
<li>One uppercase letter</li>
<li>One lowercase letter</li>
<li>One number</li>
<li>One special character (!@#$%^&*...)</li>
</ul>
</div>
</form>
);
}

Errors​

400 Bad Request​

Invalid or expired reset token:

{
"detail": "Invalid or expired reset token"
}

Reset token has expired:

{
"detail": "Reset token has expired"
}

Password doesn't meet requirements:

{
"detail": [
{
"loc": ["body", "new_password"],
"msg": "Password must contain at least one uppercase letter",
"type": "value_error"
}
]
}

404 Not Found​

User not found (token was valid but user was deleted):

{
"detail": "User not found"
}

Security Behavior​

When this endpoint is called successfully:

  1. Password is hashed and updated
  2. Reset token is marked as used (cannot be reused)
  3. All other reset tokens for this user are invalidated
  4. All verification codes for password reset are invalidated

Token Lifespan​

EventLifespan
Token created15 minutes
Token used successfullyImmediately invalidated
Token expiredCannot be used

If the token expires, the user must request a new one via password reset.

Password Validation​

Passwords are validated for:

  • Length: Minimum 8 characters
  • Uppercase: At least one (A-Z)
  • Lowercase: At least one (a-z)
  • Digit: At least one (0-9)
  • Special: At least one (!@#$%^&*(),.?":|<>)

Example valid passwords:

  • SecurePass123!
  • MyP@ssw0rd
  • C0mpl3x!ty

Example invalid passwords:

  • password (no uppercase, no digit, no special char)
  • PASSWORD123 (no lowercase, no special char)
  • Pass! (too short)

Complete Password Reset Flow​

  1. User clicks "Forgot Password" on login page
  2. User enters email
  3. Frontend calls POST /auth/password-reset
  4. User receives email with reset link
  5. User clicks link β†’ Redirected to frontend with token
  6. User enters new password (twice for confirmation)
  7. Frontend calls POST /auth/password-reset/confirm
  8. Password is reset
  9. User redirected to login
  10. User logs in with new password

Security Considerations​

  • Single-use tokens: Each token can only be used once
  • Time-limited: Tokens expire in 15 minutes
  • Password hashing: Passwords are never stored in plain text
  • Token invalidation: Using a token invalidates all other reset tokens
  • Strong password required: Enforces password complexity rules