POST /auth/forgot-password
Solicitar e-mail de reset de senha
/auth/forgot-passwordAuth: públicoInicia o fluxo de recuperação de senha. Se o e-mail informado existir na base, gera um token aleatório (32 bytes hex), persiste o sha256 dele em password_reset_tokens com TTL de 1 hora, e dispara um e-mail com link contendo o token raw.
Sempre retorna 200, independente de o e-mail existir ou não. Isso é por segurança — revelar quais e-mails existem viabiliza enumeration attacks (atacante descobre quais usuários cadastrar pra phishing).
Quando chamar
- Tela "Esqueci minha senha", após o user digitar o e-mail e submeter
- A UI deve ser idempotente com o backend: o feedback é sempre "Se o e-mail existir, você receberá as instruções em breve"
Request
| Campo | Tipo | Requerido | Descrição |
|---|---|---|---|
| string (email) | sim | E-mail cadastrado. Resposta é sempre 200 (não revela existência de conta). |
Validação: email precisa ter formato válido (Zod .email()). Esse erro vem como 400 do Fastify, não como 200 — o frontend deve tratar separado.
Response
200
| Campo | Tipo | Requerido | Descrição |
|---|---|---|---|
| message | string | sim |
{
"message": "Se o e-mail existir, você receberá as instruções em breve."
}Erros
Sem respostas de erro documentadas.
Apenas erros de validação Zod (400) podem aparecer. Não há erro específico de "e-mail não existe" — isso retorna 200 mesmo assim.
Exemplos
curl -X POST 'http://localhost:3003/auth/forgot-password' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer SEU_ACCESS_TOKEN' \
-d '{}'await fetch('http://localhost:3003/auth/forgot-password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + accessToken,
},
body: JSON.stringify({}),
})Resposta sempre é 200
{ "message": "Se o e-mail existir, você receberá as instruções em breve." }Side effects
- DB (apenas se o e-mail existir):
INSERT INTO password_reset_tokens (user_id, token_hash, expires_at)comexpires_at = now() + 1h - E-mail (apenas se o e-mail existir):
IEmailService.sendPasswordResetEmail(email, resetUrl)— o link é${APP_URL}/auth/reset-password?token=<rawToken>. Em dev (ConsoleEmailAdapter) o link aparece nos logs. - Sem timing-attack mitigation explícita: se o e-mail não existir, o backend retorna mais rápido (~2ms vs ~30ms quando precisa gerar token + insert + envio assíncrono de e-mail). Atacantes sofisticados podem detectar diferença. Mitigação opcional: medir tempo médio e aplicar
setTimeoutde equalização. Não implementado.
Relacionados
- Endpoint:
POST /auth/reset-password— passo seguinte (consome o token) - Tabela:
password_reset_tokens— onde os tokens vivem - Conceito: Autenticação