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-10definetrim: true+lowercase: true. O Mongoose aplica isso em todosave/create, então no banco todo username está minúsculo e sem espaços. - Login
src/app/lib/utils/auth.js:31-32busca 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.usernamena 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 preencherrawData(para que odefaultValuere-exibido no form já volte normalizado):const username = (formData.get("username") || "").trim().toLowerCase(); - Mantém o tratamento de
NEXT_REDIRECT/CredentialsSignincomo 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.jsxrepassa...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 loginsrc/app/auth/login/LoginForm.jsx— atributos anti auto-capitalizesrc/app/lib/users/createUserAction.js— consistência na checagem/gravaçãosrc/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
- Repro do bug (antes do fix): com um usuário existente (ex.:
joao), tentar login digitandoJoaooujoao(com espaço) → deve dar "Credenciais inválidas". - 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".
- Login com
- Mobile: abrir
/auth/loginem viewport mobile / dispositivo e confirmar que o campo Usuário não auto-capitaliza a primeira letra. - Cadastro: registrar
Maria; conferir no banco que foi salvo comomaria; tentar cadastrarmariade novo → "Nome de usuario ja cadastrado". - Rodar a app localmente (
npm run dev) e exercitar os fluxos acima; rodar a suíte de testes se existir.