Skip to content

feat: fluxo de recuperacao de senha - #25

Merged
janeiaraujo merged 6 commits into
mainfrom
feat/password-reset
Aug 3, 2026
Merged

feat: fluxo de recuperacao de senha#25
janeiaraujo merged 6 commits into
mainfrom
feat/password-reset

Conversation

@janeiaraujo

@janeiaraujo janeiaraujo commented Aug 3, 2026

Copy link
Copy Markdown
Owner

O problema

Não existia "esqueci minha senha". Quem esquecesse tinha duas saídas: magic link (que exige SMTP configurado) ou pedir a um admin para redefinir. Numa instalação sem SMTP, o usuário ficava permanentemente travado — e o admin também, se fosse ele quem esqueceu.

Decisões de segurança

Token guardado como hash. O token tem 256 bits e é gravado como SHA-256, não em texto puro. Se o banco vazar, os tokens em trânsito não servem para tomar contas — mesmo raciocínio de não guardar senha em texto puro. (SHA-256 basta aqui: o token é aleatório, não há o que forçar por dicionário como numa senha escolhida por pessoa.)

Não enumera contas. A resposta é idêntica exista ou não o e-mail, inclusive para conta inativa. Sem isso, o endpoint viraria um verificador de e-mails cadastrados. A única exceção é SMTP fora do ar, que precisa ser explícito — senão a pessoa fica esperando um e-mail que nunca vai chegar.

Uso único, prazo curto, e um pedido invalida o anterior. Token expira em 60 minutos; um novo pedido marca os antigos como usados, então só o link mais recente funciona.

Redefinir destrava a conta. Quem esqueceu a senha provavelmente errou várias vezes e acionou o bloqueio de 15 minutos do PR #23. Não faria sentido redefinir a senha e continuar preso esperando o tempo passar.

Índice TTL em password_reset_tokens — o Mongo limpa os vencidos sozinho, já que não há rotina de expurgo no app.

Frontend

Telas /forgot-password e /reset-password, link discreto no login (só no modo senha, não no magic link) e aviso de sucesso ao voltar para o login. Textos em PT e EN. Link sem token mostra uma tela de erro com o caminho de volta, em vez de um formulário que falharia no envio.

Validação

Testei a lógica com stub, cobrindo os casos que realmente importam:

ok   e-mail inexistente: sem token, sem erro (nao enumera contas)
ok   conta inativa: mesmo tratamento, sem token
ok   usuario valido: token criado
ok   token guardado como HASH (nao em texto puro)
ok   token tem prazo de validade
ok   senha com menos de 8 caracteres e recusada
ok   token invalido e recusado
ok   token expirado e recusado
ok   senha gravada com hash bcrypt
ok   redefinir destrava a conta bloqueada
ok   token e de uso unico

As três telas foram verificadas no navegador (formulário, nova senha, e link sem token).

Test plan

  • Lógica validada com stub (11 checagens)
  • Telas renderizadas no navegador
  • Com SMTP configurado: pedir recuperação, receber o e-mail e concluir a troca
  • Sem SMTP: confirmar a mensagem clara de "serviço de e-mail não configurado"
  • Confirmar que o link só funciona uma vez

Nao existia "esqueci minha senha". Quem esquecesse a senha so tinha duas
saidas: magic link (que exige SMTP configurado) ou pedir a um admin para
redefinir. Numa instalacao sem SMTP, o usuario ficava permanentemente
travado - e o admin tambem, se fosse ele quem esqueceu.

Backend:
- POST /auth/forgot-password e /auth/reset-password, com o mesmo rate
  limit das demais rotas de auth.
- Token de 256 bits guardado como HASH sha256, nao em texto puro: se o
  banco vazar, os tokens em transito nao servem pra tomar contas.
- Resposta identica exista ou nao o e-mail (inclusive para conta
  inativa), senao o endpoint viraria um verificador de contas
  cadastradas. A excecao e SMTP fora do ar, que precisa ser explicito -
  sem isso a pessoa fica esperando um e-mail que nunca vem.
- Um pedido novo invalida os anteriores; token expira em 60 min e e de
  uso unico.
- Redefinir a senha destrava a conta bloqueada por tentativas: quem
  esqueceu a senha e errou ate bloquear nao pode ficar preso esperando.
- Indice TTL em password_reset_tokens: o Mongo limpa os vencidos
  sozinho, ja que nao ha rotina de expurgo no app.

Frontend: telas /forgot-password e /reset-password, link no login e
aviso de sucesso ao voltar. Textos em pt/en.

Validado com stub nos casos que importam (11 checagens): nao enumera
contas, token so como hash, senha curta/token invalido/expirado
recusados, uso unico, e o destravamento da conta.
Copilot AI review requested due to automatic review settings August 3, 2026 18:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implementa um fluxo completo de recuperação de senha (sem depender de magic link) para destravar usuários em instalações sem SMTP/magic link, adicionando endpoints, telas e traduções, além de armazenamento seguro de tokens (hash) e expiração automática via TTL no MongoDB.

Changes:

  • Adiciona endpoints /auth/forgot-password e /auth/reset-password com criação/validação de token e envio de e-mail.
  • Cria telas públicas /forgot-password e /reset-password, com navegação/feedback no login.
  • Inclui chaves de i18n (PT/EN) e índices Mongo (incluindo TTL) para password_reset_tokens.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
frontend/src/services/api.js Adiciona métodos do client para forgot/reset password.
frontend/src/pages/auth/ResetPassword.jsx Nova tela para redefinir senha via token.
frontend/src/pages/auth/Login.jsx Link “Esqueci minha senha” e mensagem de sucesso pós-reset.
frontend/src/pages/auth/ForgotPassword.jsx Nova tela para solicitar link de recuperação.
frontend/src/i18n/locales/pt.json Textos PT para forgot/reset.
frontend/src/i18n/locales/en.json Textos EN para forgot/reset.
frontend/src/App.jsx Rotas públicas para forgot/reset.
backend/src/modules/auth/email.service.js Novo e-mail de reset de senha.
backend/src/modules/auth/auth.service.js Lógica de criação/validação de token e reset de senha.
backend/src/modules/auth/auth.routes.js Novas rotas Fastify para forgot/reset.
backend/src/db/indexes.js Índices para password_reset_tokens (inclui TTL).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread backend/src/modules/auth/auth.service.js Outdated
Comment thread backend/src/modules/auth/auth.service.js
Comment thread frontend/src/pages/auth/ResetPassword.jsx Outdated
Comment on lines +111 to +118
"reset": {
"title": "New password",
"subtitle": "Choose a password to get back into your account.",
"submit": "Reset password",
"success": "Password reset successfully. You can now sign in with your new password.",
"invalidLink": "Invalid link",
"invalidLinkHelp": "This reset link isn't valid. Request a new one."
}
Comment thread frontend/src/i18n/locales/pt.json
Comment thread backend/src/modules/auth/email.service.js Outdated
janeiaraujo and others added 5 commits August 3, 2026 15:28
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@janeiaraujo
janeiaraujo merged commit ff273cf into main Aug 3, 2026
3 checks passed
@janeiaraujo janeiaraujo mentioned this pull request Aug 3, 2026
3 tasks
@janeiaraujo
janeiaraujo deleted the feat/password-reset branch August 3, 2026 23:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants