---
title: "Forgot Password"
method: POST
path: "/api/v1/auth/forgot-password"
tags: ["auth"]
---

# Forgot Password

`POST /api/v1/auth/forgot-password`

## Request

- Base URL: `https://api.badgeia.com`
- URL: `https://api.badgeia.com/api/v1/auth/forgot-password`
- Auth: none declared

Begin a password reset (SEC-AUTH-013).

ALWAYS returns 202 with the same generic body regardless of whether the
email resolves to an account — no enumeration via status, body, or shape.
When the email DOES resolve to an email/password account, we mint a
single-use, 1h, hashed-at-rest reset token and email a link; we also emit
`password_reset_requested`.

Accounts with no password_hash (GitHub-OAuth-only) are treated as
"no account to reset" — we don't send a reset link for a password that
doesn't exist, but we still return the identical generic body.

Rate-limited via the middleware `auth` bucket (see rate_limiter
`_categorize_request`) so the email-send can't be used to mail-bomb a
victim or brute-probe the user table.

Anti-enumeration timing (security-auditor finding): the email send is a
multi-hundred-ms Resend round-trip in prod. If we awaited it inline, the
exists branch would return measurably slower than the unknown/OAuth-only
branch — a timing oracle that re-enables enumeration despite the
identical response shape. So the send is dispatched as a BackgroundTask,
which runs AFTER the response is flushed; both branches return on the
same fast timeline (the in-request work is only a sub-ms token mint +
audit insert).

## Request body

- ForgotPasswordRequest: Body for POST /auth/forgot-password. Only the email — the response is deliberately generic (no enumeration) regardless of whether it resolves.
  - `email` string, email, required

## Response `202`

Successful Response

- object

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/badgeia/apis/badge.md) · [All operations](https://skmtc.dev/badgeia/apis/badge/llms.txt) · [OpenAPI document](https://skmtc.dev/badgeia/apis/badge/revisions/7e7f7fee8b77?raw)
