O ingresso com holograma
O ingresso traz nome, setor e validade impressos, com um holograma difícil de forjar. A catraca olha o holograma e a data — não liga para a bilheteria a cada pessoa. Mas se alguém fotografa o ingresso (copia o token), usa até vencer; rasgar na saída (logout) não invalida a foto.
Estado no cliente, confiança na assinatura
O valor do JWT é verificar sem round-trip. O preço é carregar claims e aceitar a janela até o exp.
Bibliotecas permissivas e alg: none já quebraram sistemas reais — a verificação é parte do produto.
Access de minutos + refresh rotativo é o padrão moderno. Refresh em cookie httpOnly reduz roubo via XSS; access em memória no SPA também ajuda.
Não coloque permissões mutáveis e sensíveis só no JWT sem revalidar: um admin demovido continua admin até o token expirar.
Como isso aparece na prática
API entre serviços
Cenário
O gateway valida o JWT uma vez e passa identidade aos serviços internos.
Como o padrão entra
Access 15min, audience/issuer checados, roles lidas com cautela para decisões críticas.
Trade-off: Revogar um token comprometido exige denylist ou esperar o exp — planeje o TTL.
SPA que guardava JWT no localStorage
Cenário
Um XSS em um widget de chat exfiltra o access token e o atacante chama a API de outro país.
Como o padrão entra
Migrar refresh para cookie httpOnly; access só em memória; CSP e sanitização.
Trade-off: Fluxo um pouco mais complexo (refresh silencioso) em troca de não entregar a chave ao XSS.
Onde isto dá errado
Confiar no alg do header
Atacante manda
alg: noneou troca RS256 por HS256 com a chave pública. Fixe a allowlist de algoritmos na verificação.Access eterno
Token de 30 dias no localStorage é sessão roubável. TTL curto + refresh.
JWT = autenticação completa
JWT é formato de credencial. Login, MFA, sessão e autorização continuam sendo problemas à parte.
Assinar e verificar com algoritmo fixo
import { SignJWT, jwtVerify } from "jose";
// Access curto + refresh longo. O access viaja no Authorization;
// o refresh mora em cookie httpOnly — nao no localStorage.
const access = await new SignJWT({ sub: userId, roles: ["user"] })
.setProtectedHeader({ alg: "HS256" })
.setIssuedAt()
.setExpirationTime("15m")
.sign(chave);
// Verificar: rejeitar alg "none", checar exp, e NAO confiar em claims
// que o cliente inventou. A assinatura e a chave sao a prova.
async function autenticarBearer(header: string | undefined) {
if (!header?.startsWith("Bearer ")) return null;
const token = header.slice(7);
const { payload } = await jwtVerify(token, chave, { algorithms: ["HS256"] });
return { id: String(payload.sub), roles: payload.roles as string[] };
}Quando usar × quando evitar
Use quando
2- APIs e federação onde verificação local importa.
- Access tokens de OAuth/OIDC com vida curta.
Evite quando
2- Logout imediato sem denylist e sem TTL curto.
- Payload com segredos ou dados que mudam a cada minuto.
Testar o que ficou
3 armadilhas de JWT viram perguntas, com o nome do padrão escondido, misturadas com padrões parecidos.
Onde isto aparece de verdade
Você já usa isto, talvez sem saber o nome.
Authorization: Bearer …O header padrão de APIs que carregam um access token JWT em cada chamada.jwt.io / bibliotecas joseFerramentas e libs que assinam e verificam tokens — o playground não é o desenho de produção.access + refresh do OAuthAccess JWT curto; refresh opaco ou JWT longo, de preferência em cookie httpOnly.
O padrão em uma linha
Sem nome de domínio, sem cerimônia. Só a ideia.
// Claims assinadas, vida curta — verificar assinatura e exp.
const { payload } = await jwtVerify(token, chave);O que ele cobra
1 salto a mais entre a chamada e o efeito.
- Revogação imediata é difícil: o token vale até expirar, a menos que haja denylist ou rotação de chave
- Claims grandes incham cada request; chaves e algoritmos mal configurados abrem buracos clássicos
Não vale se: você precisa de logout imediato e sessão centralizada simples — cookie de sessão opaca costuma ser mais honesto.
Costuma ser confundido com
Onde isto aparece
Continue por aqui
- AutenticaçãoAutenticação responde *quem você é*: prova de identidade antes de qualquer permissão. Na web, o desenho padrão é sessão no servidor com cookie httpOnly, Secure e SameSite — o token opaco mora fora do alcance do JavaScript da página. Confundir autenticação com autorização, ou guardar a prova de identidade no localStorage, é o caminho mais curto para vazamento e abuso.
- OAuth 2.0OAuth 2.0 é delegação de acesso: um cliente obtém autorização para agir em nome do usuário sem ver a senha dele. O fluxo moderno é Authorization Code com PKCE; o implícito morreu. OIDC acrescenta identidade (id_token) em cima. Inventar “OAuth caseiro” com senha no body de um SPA costuma ser pior que sessão clássica bem feita.
- Autorização (RBAC e guards)Autorização responde *o que você pode fazer* depois de autenticado. RBAC (roles) e guards/middleware — Nest guards, Next middleware, Express — concentram a decisão perto da rota ou do caso de uso. “Tem `req.user`” não é autorização; IDOR e checagem só no front são as falhas clássicas.
- API GatewayNum sistema de muitos serviços, um ponto único de entrada por onde tudo passa: o API Gateway roteia cada requisição ao serviço certo e concentra o que é transversal — autenticação, rate limiting, CORS, log — para os serviços não repetirem isso cada um. O cliente conhece só o gateway, e a topologia interna pode mudar por trás. O risco é o gateway virar gargalo, ponto único de falha, ou um monólito de fronteira inchado de regra.