SegurançaIntermediário8 min de leitura5 seções2015, Data conhecida

JWT

JSON Web Token é um formato de credencial assinada: o servidor (ou o IdP) embute claims e uma assinatura, e quem recebe verifica sem necessariamente consultar um store de sessão. Útil para APIs e SSO — perigoso quando vira “auth completo” com token eterno no localStorage, algoritmo `none`, ou sem plano de refresh e revogação.

Em 10 segundos

JWT é credencial assinada com claims e prazo. Bom para APIs e SSO; ruim como desculpa para token eterno no localStorage. Access curto, verificação com algoritmos fixos, refresh fora do alcance do XSS.

Antes de ter nome

Tickets assinados e cookies de sessão — o JWT desloca o estado para um payload verificável no cliente.

  • #seguranca
  • #jwt
  • #token
  • #bearer
  • #claims
  • #oauth
Analogia

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.

01Conceito

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.

02No mundo real

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.

03Cuidado

Onde isto dá errado

  1. Confiar no alg do header

    Atacante manda alg: none ou troca RS256 por HS256 com a chave pública. Fixe a allowlist de algoritmos na verificação.

  2. Access eterno

    Token de 30 dias no localStorage é sessão roubável. TTL curto + refresh.

  3. JWT = autenticação completa

    JWT é formato de credencial. Login, MFA, sessão e autorização continuam sendo problemas à parte.

04Implementação

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[] };
}
05Decisão

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