JWT: o que é, e sobretudo o que não é
O JSON Web Token é três blocos de texto separados por pontos. Vale a pena saber exatamente o que cada um faz, porque quase todos os erros com JWT vêm de lhe atribuir propriedades que ele não tem.
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMiLCJub21lIjoiQW5hIn0.4pcPyMD09olPSyXnrXCjTw
└── cabeçalho ──────┘ └── dados ─────────────────────┘ └── assinatura ───┘1. Não é encriptado
Aquilo é base64, não é cifra. Qualquer pessoa com o token lê o conteúdo — sem chave nenhuma, numa linha:
JSON.parse(atob('eyJzdWIiOiIxMjMiLCJub21lIjoiQW5hIn0'));
// { sub: '123', nome: 'Ana' }A assinatura garante que ninguém alterou o conteúdo. Não garante que ninguém o leu. Nunca ponha lá dentro nada que não queira ver escrito num ecrã.
2. Não se pode desfazer
É a diferença que interessa face a uma sessão guardada em base de dados. Uma sessão apaga-se e acabou. Um JWT válido até às 15:42 continua válido até às 15:42, mesmo depois de expulsar a pessoa, mudar-lhe a password ou apagar-lhe a conta.
As saídas são sempre variações do mesmo: validade curta — minutos, não dias — mais um refresh token guardado do lado do servidor, esse sim revogável.
3. Onde é que ele fica
Num cookie
httpOnly: o JavaScript da página não lhe toca, portanto um XSS não o rouba. Exige atenção ao CSRF, que se trata comSameSite.No
localStorage: qualquer script que corra na página o lê. E "qualquer script" inclui o de uma dependência que foi comprometida a semana passada.
A primeira opção é a que se recomenda, e é a que este site usa.
4. Verificar como deve ser
import jwt from 'jsonwebtoken';
const dados = jwt.verify(token, process.env.SEGREDO, {
// Sem isto, um token assinado com 'alg: none' já foi aceite por
// bibliotecas a sério. Diga sempre qual é o algoritmo que espera.
algorithms: ['HS256'],
});E a regra final: descodificar não é verificar. Um jwt.decode() lê o conteúdo sem confirmar a assinatura — é útil para depurar, e é uma porta escancarada se aparecer no caminho de autenticação.