O processo acontece em 3 chamadas sequenciais. Cada etapa depende do resultado da anterior:
1. POST /password/reset-code → dispara o código por e-mail
2. POST /password/verify-code → troca o código pelo reset_token
3. POST /password/reset → usa o reset_token para definir a nova senha
O reset_token obtido na Etapa 2 é obrigatório na Etapa 3 e tem validade curta (10 minutos). O código enviado por e-mail é usado apenas na Etapa 2 — ele nunca deve ser reenviado nas etapas seguintes.Todas as requisições e respostas usam Content-Type: application/json.
{"message":"Se este e-mail estiver cadastrado, você receberá um código em instantes."}
⚠️ Importante: esta resposta é sempre a mesma, independente de o e-mail existir ou não na base — é uma proteção intencional contra enumeração de usuários. A aplicação cliente não deve tentar inferir se o e-mail existe a partir da resposta; trate sempre como sucesso e avance para a tela de inserção do código.
O código não diferencia maiúsculas de minúsculas na exibição, mas recomenda-se normalizar para uppercase antes de enviar (code.toUpperCase()), já que é assim que ele é gerado e comparado no backend.
{"message":"Código verificado com sucesso.","reset_token":"8f3a1c9e2b7d4f6a...(64 caracteres)","expires_in":600}
Campo
Tipo
Descrição
reset_token
string
Token opaco a ser enviado na Etapa 3. Não decodifique nem tente interpretar seu conteúdo — é uma string aleatória sem significado próprio.
expires_in
number
Tempo de validade do token, em segundos, a partir do momento desta resposta
💡 Use expires_in para exibir um contador regressivo na tela de nova senha (ex: Date.now() + expires_in * 1000). Não assuma um valor fixo no cliente — o backend pode alterar essa janela.
Retornado quando o código está incorreto, expirado, ou o limite de tentativas foi excedido. A mensagem é sempre genérica por design, para não revelar qual foi a causa exata:
{"message":"Código inválido ou expirado."}
Trate esse status como "peça ao usuário para conferir o código ou solicitar um novo" — não exponha detalhes técnicos na UI.
A senha é validada no backend com os seguintes critérios (a aplicação cliente deve replicar essa validação no formulário para dar feedback imediato ao usuário, mas o backend é sempre a fonte de verdade):
Regra
Detalhe
Comprimento mínimo
8 caracteres
Comprimento máximo
64 caracteres
Letra
Ao menos uma (a-z ou A-Z)
Número
Ao menos um (0-9)
Caractere especial
Ao menos um (qualquer caractere fora de a-zA-Z0-9)
Vazamentos conhecidos
A senha é checada contra bases de vazamento conhecidas; se comprometida, é rejeitada mesmo atendendo aos critérios acima
{"message":"Senha redefinida com sucesso. Faça login com sua nova senha."}
Após esta resposta, todas as sessões e tokens de acesso anteriores do usuário são revogados no backend. Se a aplicação cliente mantinha alguma sessão ativa desse usuário em outra aba/dispositivo, ela deixará de ser válida — a aplicação deve redirecionar para a tela de login.
Pode ocorrer por dois motivos — verifique o campo message para diferenciar:Token inválido/expirado:
{"message":"Token de redefinição inválido ou expirado."}
→ Reinicie o fluxo a partir da Etapa 1.Senha não atende à política:
{"message":"A senha não atende aos requisitos mínimos de segurança.","errors":{"password":["A senha não atende aos requisitos mínimos de segurança."]}}
→ Mantenha o usuário na mesma tela e destaque os requisitos não atendidos.
Nenhum dos três endpoints requer token de autenticação (Bearer/API key) — o próprio reset_token da Etapa 2 cumpre esse papel de forma escopada e temporária.
Não persista o reset_token em localStorage ou sessionStorage. Mantenha-o apenas em memória (estado do componente/aplicação). Se a página for recarregada, force o reinício do fluxo a partir da Etapa 1 — isso é esperado e reduz a superfície de exposição do token.
Não exiba mensagens de erro diferentes com base em suposições próprias. Os status 422 das Etapas 1 e 2 são propositalmente genéricos — reproduza a mensagem do backend (message) sem tentar adivinhar ou complementar com informação adicional (ex: não diga "esse e-mail não existe").
Trate a expiração do reset_token no cliente também, usando expires_in, para não deixar o usuário preencher um formulário que o backend já vai rejeitar por expiração.
Sempre reinicie o fluxo do zero (Etapa 1) quando: o token expirar, o código expirar/exceder tentativas, ou o usuário fechar/recarregar a página no meio do processo. Não há endpoint de "retomada" — cada tentativa de recuperação é uma sequência nova e completa.
Após sucesso na Etapa 3, redirecione para a tela de login. Não tente reaproveitar nenhuma sessão anterior — ela foi revogada no backend.