Files
course-plat/PLANO-FIX-LOGIN-CREDENCIAIS.md
T
2026-08-31 14:10:20 -03:00

5.2 KiB

Correção: login falha ("Credenciais inválidas") para alguns usuários com senha correta

Contexto

Usuários relatam, de forma intermitente entre pessoas (não para todos), que digitam a senha correta e recebem "Credenciais inválidas". A hipótese inicial ("será que está logando mas mostra erro?") foi descartada: em src/app/lib/userLoginAction.js o signIn em caso de sucesso lança NEXT_REDIRECT, que é corretamente relançado (linhas 32-39), redirecionando para /dispatcher. Não existe caminho de sucesso que ainda exiba o erro. Trata-se de uma falha real de autenticação (nenhuma sessão é criada).

Causa raiz

O username é gravado normalizado mas consultado cru:

  • Schema src/app/models/User.js:9-10 define trim: true + lowercase: true. O Mongoose aplica isso em todo save/create, então no banco todo username está minúsculo e sem espaços.
  • Login src/app/lib/utils/auth.js:31-32 busca com o valor cru: User.findOne({ username: credentials.username }). O MongoDB faz match case-sensitive.

Resultado: quem cadastrou Joao (salvo como joao) e faz login digitando Joao gera busca por "Joao" → nenhum match → null → "Credenciais inválidas", sem nem comparar a senha.

Por que "alguns sim, outros não"

Quem digita o usuário todo em minúsculo entra; quem digita com maiúscula/espaço falha sempre (consistente por usuário, não aleatório). Gatilho principal: teclado de celular auto-capitaliza a primeira letra, e o input de login (src/app/auth/login/LoginForm.jsx:31-37) não tem autoCapitalize/autoCorrect/autoComplete. Autofill com espaço final tem o mesmo efeito. Daí o padrão "mobile reclama, desktop não".

Observação sobre dados: não é necessária migração de banco. Como o Mongoose já força lowercase em toda gravação, não há usernames mixed-case armazenados — apenas a consulta precisa ser corrigida.

Abordagem (escopo robusto)

1. Normalizar a consulta no provider de auth (correção central)

src/app/lib/utils/auth.js

  • Derivar um username normalizado uma vez e usá-lo na consulta:
    const username = (credentials.username || "").trim().toLowerCase();
    const password = credentials.password;
    ...
    const user = await User.findOne({ username }).lean();
    
  • Remover o uso duplicado de credentials.username na linha 32 (usar a variável já tratada).

2. Normalizar também no server action de login

src/app/lib/userLoginAction.js

  • Após formData.get("username"), normalizar antes de validar/enviar e antes de preencher rawData (para que o defaultValue re-exibido no form já volte normalizado):
    const username = (formData.get("username") || "").trim().toLowerCase();
    
  • Mantém o tratamento de NEXT_REDIRECT/CredentialsSignin como está.

3. Endurecer o input de login contra auto-capitalização (mobile)

src/app/auth/login/LoginForm.jsx — no UIInput de name="username" adicionar: autoCapitalize="none", autoCorrect="off", spellCheck={false}, autoComplete="username".

  • Confirmar que src/components/ui/input.jsx repassa ...props (já repassa), então os atributos fluem para o <input> nativo.

4. Alinhar a checagem de duplicado no cadastro

src/app/lib/users/createUserAction.js:131 — a verificação findOne({ username }) usa o valor cru e é case-sensitive, enquanto o User.create grava lowercased. Normalizar o username logo na leitura (linha 24) para (formData.get("username") || "").trim().toLowerCase(), de modo que a checagem de duplicado, a mensagem de erro re-exibida e o valor gravado fiquem consistentes. A validação de "sem espaços" (linha 55) continua válida.

  • Aplicar a mesma normalização de leitura em createWardUserAction.js (criação de ward) para manter consistência, caso ele leia username de formData da mesma forma.

Arquivos críticos

  • src/app/lib/utils/auth.js — fix central da consulta (CRÍTICO)
  • src/app/lib/userLoginAction.js — normalização do input do login
  • src/app/auth/login/LoginForm.jsx — atributos anti auto-capitalize
  • src/app/lib/users/createUserAction.js — consistência na checagem/gravação
  • src/app/lib/users/createWardUserAction.js — mesma consistência
  • (referência, sem alteração) src/app/models/User.js, src/components/ui/input.jsx

Verificação

  1. Repro do bug (antes do fix): com um usuário existente (ex.: joao), tentar login digitando Joao ou joao (com espaço) → deve dar "Credenciais inválidas".
  2. Depois do fix:
    • Login com Joao, JOAO, joao, joao → todos devem autenticar e redirecionar para /dispatcher.
    • Senha errada → continua "Credenciais inválidas" (regressão de segurança garantida).
    • Usuário inexistente → "Credenciais inválidas".
  3. Mobile: abrir /auth/login em viewport mobile / dispositivo e confirmar que o campo Usuário não auto-capitaliza a primeira letra.
  4. Cadastro: registrar Maria; conferir no banco que foi salvo como maria; tentar cadastrar maria de novo → "Nome de usuario ja cadastrado".
  5. Rodar a app localmente (npm run dev) e exercitar os fluxos acima; rodar a suíte de testes se existir.