Nunca guarde senhas em texto plano
Guarde sempre o hash da senha, não a senha. E não qualquer hash: use um lento e com sal pensado para isso, como bcrypt, scrypt ou argon2.
- Sal (salt): um valor aleatório único por usuário que se mistura antes de fazer o hash. Faz com que duas pessoas com a mesma senha tenham hashes diferentes e quebra os ataques com tabelas pré-calculadas (rainbow tables).
- Lento de propósito: o bcrypt é custoso de calcular, o que freia os ataques de força bruta.
senha + sal ──bcrypt──> $2b$10$N9qo8uLOick... (isto é o que você guarda)
No login, você refaz o hash do que o usuário digita e compara hashes; nunca recupera a senha original (não dá, e isso é bom).
Outras regras de ouro
- HTTPS sempre: sem TLS, qualquer um na rede pode ler o token ou a senha em trânsito. A credencial viaja em texto plano sem ele.
- Não coloque segredos no payload do token: lembre-se, ele é legível por qualquer um. Nada de senhas nem dados sensíveis dentro do JWT.
- Validade curta + refresh: access tokens de vida breve e um refresh token para renovar. Reduz a janela de dano se roubarem um token.
- Logout e revogação: um JWT stateless não pode ser "apagado" do cliente, então para revogá-lo de verdade você mantém uma lista de revogação (ou invalida o refresh token) no servidor. As sessões, por outro lado, são revogadas simplesmente apagando-as do armazenamento.
- Cookies seguros: se você usa cookies, marque-os como
httpOnly,SecureeSameSitepara mitigar XSS e CSRF de uma vez.
Exemplos
Verificar validade: comparar exp com o momento atual
const agora = Math.floor(Date.now() / 1000);
const payload = { sub: "ana", exp: agora - 60 }; // caducou há 1 minuto
console.log(payload.exp < agora ? "caducado" : "válido");