JWT (JSON Web Token / jwt decoder / jwt online / decode jwt) nao e criptografia, e codificacao — o payload usa base64url que decodifica para texto plano em um segundo, entao nunca coloque senhas / PII / cartoes bancarios / numeros de telefone no payload JWT. Este artigo cobre 8 foot-guns reais de seguranca JWT + 5 cenarios de ataque de falsificacao + plano de protecao 7 dias, que juntos evitam pelo menos 90% das vulnerabilidades.
Resumo em 30 Segundos
- JWT nao e criptografia, e codificacao — muitos desenvolvedores pensam que JWT e “seguro” porque a codificacao base64url parece ilegivel, mas qualquer pessoa pode decodificar em um segundo para obter o payload em texto plano. JWT payload = texto plano, apenas assinado, nao criptografado
- JWT padrao 4 riscos principais: ataque
alg=none/ confusao de chave publica HS256 vs RS256 /expnao validado permite que tokens expirados passem / remocao de assinatura algumas bibliotecas aceitam como fallback - Implantacao JWT 4 foot-guns: JWT secret hardcoded em Git scaneado em horas / injecao de kid qualquer arquivo usado como chave / sem blacklist tokens antigos validos apos logout / expiracao longa (7 dias) mudanca de senha nao invalida tokens
- 5 cenarios reais de ataque: vazamento de telefone em texto plano / falsificacao alg=none / assinatura HS256 com chave publica / exp nao validado / remocao de assinatura passa validacao
- Plano de protecao 7 dias (cada um ≤ 30 minutos): forcar whitelist de algoritmo (sempre verificar exp) / JWT secret via env vars + .gitignore / validacao estrita de formato kid (whitelist de caracteres) / assinatura deve verificar (none rejeitado) / expiracao curta (15 minutos) + rotacao de refresh token / blacklist + estado revoke em BD / nunca colocar PII em payload JWT
- Use o Decodificador JWT Piick localmente para decodificar tokens suspeitos e verificar header / payload / exp / assinatura — 100% local sem upload, nao polui seu log de auditoria durante o debug
8 Foot-Guns Reais de JWT
Foot-Gun 1: JWT Nao E Criptografia, E Codificacao
Sintoma: Voce coloca o numero de telefone / email / ultimos 4 digitos do cartao / hash de identificacao do usuario no payload JWT, pensando “o token parece texto ilegivel, outros nao conseguem ler”. Ate que um dia o payload vaza, base64url decodifica — telefone + email + hash de ID em texto plano tudo exposto, multa de conformidade GDPR a partir de ¥500k.
Por que: JWT tem tres segmentos header.payload.signature, apenas a assinatura esta assinada (HMAC/RSA assinada para evitar manipulacao), mas o payload em si e texto plano codificado com base64url. Qualquer pessoa com o token (incluindo logs de frontend / CDN / proxy reverso / DevTools do navegador) pode atob(token.split('.')[1]) decodificar para JSON em um segundo. JWT nao e criptografia, e “texto plano a prova de manipulacao”.
Correcao:
- Nunca coloque PII (Informacao de Identificacao Pessoal) no payload JWT — sem telefone / email / cartao de identificacao / cartao bancario / endereco / hash de senha
- O payload JWT so contem “identificadores nao sensiveis” — user_id (UUID de banco de dados, nao numero derivavel), role (papel, nao estrutura organizacional), exp / iat / nbf (timestamps)
- Campos verdadeiramente sensiveis: coloque no banco de dados do backend, o JWT so tem user_id, consulte o BD quando necessario
- Se voce realmente precisa de dados sensiveis no token: use JWE (JSON Web Encryption) — mas 99% dos cenarios nao precisam
Cenario real: Uma empresa SaaS colocou numeros de telefone de usuarios diretamente no payload JWT (para “economizar uma consulta ao banco de dados”), 3 meses depois o JWT secret vazou, 2 milhoes de telefones de usuarios obtidos atraves de decodificacao do payload em um clique, multas duplas GDPR + Lei de Protecao de Informacao Pessoal da China ¥8 milhoes.
Foot-Gun 2: Ataque alg=none
Sintoma: Sua biblioteca JWT e antiga (jwt-go versao antiga / jsonwebtoken antes de 4.x / python-jose versao velha), um atacante constroi header = {"alg": "none"} + payload arbitrario, forja um token admin, sua biblioteca do servidor aceita, o atacante obtem diretamente privilegios de admin.
Por que: O padrao JWT antigo RFC 7519 nao exigia a validacao do lado do servidor do campo alg, algumas bibliotecas ao ver alg: "none" confiam diretamente no payload sem verificar a assinatura (porque “none” = “sem assinatura”, a biblioteca pula o passo de verificacao). Este e o ataque mais classico na historia do JWT, em 2015 Auth0 e outras bibliotecas multiplas foram afetadas.
Correcao:
- Forcar whitelist de algoritmo (sempre especifique algoritmos permitidos): jsonwebtoken.verify com whitelist de algoritmos: [‘HS256’]
- Sempre rejeitar
alg: "none"(mesmo se compativel com RFC) - Atualizar para a ultima versao da biblioteca JWT (corrige vulnerabilidades conhecidas de alg=none)
- Revisao de codigo verificando chamadas verify — sem parametro de algoritmos especificado e uma vulnerabilidade
Cenario real: Relatorio publico da Auth0 2015: biblioteca Node.js jsonwebtoken versoes antes de 4.2.2 aceitam alg: "none" por padrao, qualquer servidor que aceite tokens sem atualizar estava sob ataque. Apos o conserto todas as bibliotecas modernas exigem especificar algoritmos.
Foot-Gun 3: Ataque de Confusao de Chave Publica HS256 vs RS256
Sintoma: Voce usa RS256 (RSA assimetrico), chave publica colocada no frontend / gateway para verificar tokens, mas algum desenvolvedor escreveu a funcao verify, ao ver header alg: "HS256" usa a mesma chave publica como secret HMAC para verificar. O atacante obtem a chave publica (ja e publica) → usa a chave publica como secret HMAC para assinar token HS256 → o servidor usa a mesma chave publica para “verificar”, passa → token admin falso burla autenticacao.
Por que: RS256 usa chave privada RSA para assinar, chave publica para verificar; HS256 usa o mesmo secret tanto para assinar quanto para verificar. Se o codigo do servidor confunde “tenho uma chave, use-a”, o atacante pode usar qualquer tipo de chave para forjar tokens. Esta e a vulnerabilidade mais classica na implantacao de RS256.
Correcao:
- Sempre forcar que o alg no header corresponda ao algoritmo configurado — algoritmo escrito na config (servico RS256 sempre verifica alg=RS256 esperado)
- secret / chave publica com nomes estritamente separados (evitar confusao): const JWT_PRIVATE_KEY = …; // so para assinar const JWT_PUBLIC_KEY = …; // so para verificar
- Revisao de codigo verificando funcao verify — forcar lista de algoritmos verify (whitelist), nao aceitar alg auto-reportado do token
- Use bibliotecas JWT maduras (PyJWT / jsonwebtoken / java-jwt) em vez de implementar verify voce mesmo
Cenario real: 2018 o servico de gateway JWT de um banco usou RS256, mas a funcao verify tinha um bug de implementacao: jwt.verify(token, publicKey) nao especificava algoritmos, o atacante usou a chave publica como secret HMAC para assinar token HS256 passando a verificacao, forjou transferencia de $10 milhoes.
Foot-Gun 4: Campo exp Nao Validado ou Validacao Vazada
Sintoma: Seu JWT tem campo exp (tempo de expiracao), assumindo validacao automatica, mas alguma rota de codigo marginal no servidor so verifica a assinatura nao exp (por exemplo, uma rota de fallback), os tokens expirados continuam sendo aceitos, a sessao nunca expira. O usuario muda senha / e desabilitado / faz logout, o token continua sendo utilizavel ate que exp expire.
Por que: O padrao JWT RFC 7519 § 4.1.4 especifica que exp e MUST validate, mas muitas bibliotecas nao forcam a validacao de exp por padrao (por compatibilidade com certos cenarios como “tokens permanentes”). Se a chamada verify nao passa explicitamente ignoreExpiration: false ou verifica manualmente no codigo em vez de usar a biblioteca, exp e omitido.
Correcao:
- Sempre verificar exp explicitamente (nao depender de valores padrao): jwt.verify com algorithms: [‘HS256’] e ignoreExpiration: false
- Tempo de expiracao curto (access token 15 minutos, refresh token 7-30 dias)
- relogio do servidor sincronizado com NTP (evitar desvio do relogio que cause expiracao prematura / tardia do token)
- O cliente nao deve confiar no tempo local — use
Date.now()/time.time()e o tempo do servidor para calcular a diferenca de exp
Cenario real: A expiracao do access token de um servico SaaS era de 7 dias, um usuario mudou a senha mas o atacante usou o token antigo, pode acessar todos os recursos do usuario durante 7 dias. Encurtar para 15 minutos + rotacao de refresh token e o padrao da industria.
Foot-Gun 5: Vazamento de JWT Secret / Chave Privada Hardcoded em Git
Sintoma: Voce escreve `const JWT_SECRET=*** em codigo + commit + push para GitHub (mesmo repositorio privado, saida de funcionario / roubo de conta / vazamento interno). O secret scanning do GitHub escaneia em 30 segundos, o JWT secret vaza igual as API keys, o atacante usa este secret para assinar tokens para qualquer usuario qualquer payload, todo o sistema comprometido.
Por que: O historico do Git nunca e apagado (git filter-branch so altera o ponteiro do branch, os objetos commit antigos permanecem em .git/objects/ por 30 dias). O JWT secret e o mesmo nivel de desastre que a API key apos o vazamento — o atacante obtem o secret = todo o sistema de autenticacao comprometido = identidade de usuario arbitrariamente falsificada.
Correcao:
- JWT secret via env vars + .gitignore: const JWT_SECRET=*** Nunca hardcode em codigo
- CI usa OIDC / tokens de curto prazo, sem secrets de longo prazo
- JWT secret igual a rotacao + monitoramento de API key — o plano de protecao de 7 dias do batch-24 api-key-leak-prevention aplica completamente
Cenario real: Uma empresa fintech jwt-secret escrita em config/default.json commitada no GitHub, o secret scanning do GitHub 30 segundos email + webhook para o atacante, em 1 hora 2 milhoes de JWTs de usuarios re-assinados, saldos de usuarios arbitrariamente manipulados. Correcao: mover secret para Vault / AWS Secrets Manager + CI OIDC.
Foot-Gun 6: Ataque de Injecao de kid (Key ID)
Sintoma: Voce usa arquitetura RS256 multi-chave, o campo kid no header especifica qual chave publica usar, o servidor getKey(header.kid) consulta a tabela de chaves publicas baseado em kid. O atacante constroi kid: "../../etc/passwd" ou kid: "' OR 1=1--", algumas bibliotecas JWT diretamente fs.readFileSync(getKey(kid)) ou concatenam consulta SQL, causando leitura arbitraria de arquivos / injecao SQL.
Por que: O campo kid foi pensado para ser “qual chave usar para verificar”, mas as bibliotecas ao implementar getKey frequentemente tratam kid como nome de arquivo / parametro SQL / caminho URL, sem validacao de caracteres whitelist. O atacante usa kid para path traversal (LFI / RCE) ou injecao SQL.
Correcao:
- kid whitelist estrito de caracteres (apenas permitir
[A-Za-z0-9_-]): validar kid com regex whitelist (alfanumerico + hifen + underscore, 1-32 caracteres) - O valor kid deve estar no conjunto de chaves conhecido (verificacao Map.has(kid))
- Nao tratar kid como nome de arquivo / parametro SQL / caminho URL
- Use bibliotecas JWT maduras (implementar getKey voce mesmo e facil que tenha bugs)
Cenario real: Node.js jsonwebtoken + alguns plugins suportam o campo jwk do header, o atacante constroi jwk: [objeto com chave controlada pelo atacante], faz com que o servidor use a chave fornecida pelo atacante para verificar = definitivamente passa. Correcao: rejeitar campos jwk / jku / x5u proprios do token, apenas usar a chave configurada no servidor.
Foot-Gun 7: Ataque de Remocao de Assinatura
Sintoma: Quando voce escreve a funcao verify, se alguma condicao limite (por exemplo, header.alg nao corresponde a whitelist) nao e tratada, algumas bibliotecas caem em aceitar o token sem assinatura (header.payload. seguido de string vazia). O atacante modifica o payload (por exemplo, muda role para admin) → remove a assinatura → alguma rota de fallback pula a verificacao de assinatura → token falso passa a validacao.
Por que: O formato JWT e header.payload.signature, se apenas header.payload. for passado, a biblioteca analisa o segmento de assinatura como vazio, algumas implementacoes de bibliotecas if (!signature) return payload (porque “sem assinatura = nao precisa verificar”), burla toda a verificacao de assinatura.
Correcao:
- Sempre verificar os 3 segmentos completos (
header.payload.signaturetodos devem ter conteudo) - Rejeitar tokens com assinatura vazia (mesmo se compativel com RFC)
- Sempre usar bibliotecas maduras (nao dividir + verificar voce mesmo)
- Caso de teste: construir
header.payload.enviar, deve ser rejeitado
Cenario real: Bug de implementacao de alguma biblioteca JWT: quando a assinatura esta vazia diretamente retorna payload, o atacante captura um token valido → modifica o payload (role → admin) → remove a assinatura → passa a validacao → obtem privilegios de admin. Correcao: antes de verify verificar token.split(’.‘).length === 3 e o terceiro segmento nao esta vazio.
Foot-Gun 8: A Lista de Revogacao de JWT Nao Existe
Sintoma: O usuario muda senha / e desabilitado pelo admin / faz logout ativamente, o token antigo continua valido ate que exp expire. A expiracao do access token de 7 dias significa que o atacante usando o token antigo pode acessar durante 7 dias apos a mudanca de senha. Sem mecanismo de blacklist / revoke = uma vez que o JWT e emitido nao da para gerenciar.
Por que: JWT e projetado para ser stateless — o servidor nao armazena tokens, apenas verifica a assinatura. Bom para escalonamento horizontal, ruim para revogacao. Se voce quer “revogar imediatamente este token”, deve ter blacklist ou mecanismo de refresh token.
Correcao:
- Access token de expiracao curta + rotacao de refresh token: access token: expiracao de 15 minutos refresh token: expiracao de 7 dias, apos cada uso regenerar novo (rotacao, o refresh token antigo e invalidado)
- refresh token armazenado em BD + blacklist (marcar o refresh token como revogado ao fazer logout)
- Revogar todos os refresh tokens ao mudar a senha (forcar re-login)
- Redis blacklist (cenarios de acesso de alta frequencia usam Redis para cachear tokens revogados, TTL = validade restante do token)
Cenario real: Um usuario SaaS mudou a senha mas o atacante usou o token roubado acessou durante 7 dias → email do usuario modificado / cartao de credito adicionado → so descoberto apos a reclamacao do servico ao cliente. Correcao: access token 15 minutos + rotacao de refresh token + mudanca de senha revoga todos os refresh tokens.
5 Cenarios Reais de Ataque
Cenario 1: Vazamento de Telefone em Texto Plano
Sintoma: Uma API SaaS retorna JWT do usuario contendo {user_id: 123, phone: "13812345678", email: "user@example.com"}, o frontend usa este token para mostrar o estado “logado”. 3 meses depois o JWT secret vaza, todos os tokens decodificados, 2 milhoes de telefones + emails de usuarios obtidos em um lote.
Correcao:
- O payload JWT so contem user_id (UUID, nao numero derivavel)
- Quando o frontend precisa mostrar o telefone, usa user_id para chamar a API do backend para consultar (nao confie na decodificacao do token)
- Nunca coloque PII no payload JWT
Cenario 2: Token Falsificado com alg=none
Sintoma: Um servico Node.js antigo usa jsonwebtoken@4.2.1, o verify nao especifica algoritmos, o atacante constroi header = {"alg": "none", "typ": "JWT"} + payload {user_id: 1, role: "admin"} + assinatura deixada vazia, diretamente forja token admin passando a validacao.
Correcao:
- Forcar whitelist de algoritmos:
jwt.verify(token, secret, { algorithms: ['HS256'] }) - Atualizar jsonwebtoken para a ultima versao
Cenario 3: Ataque de Confusao de Chave Publica HS256
Sintoma: O servico JWT de um banco usa RS256 (chave privada assina, chave publica verifica), chave publica no gateway da API, funcao verify jwt.verify(token, publicKey) nao especifica algoritmos. O atacante usa a chave publica como secret HMAC para assinar token HS256, o servidor usa a chave publica para “verificar”, passa → token admin falso transfere $10 milhoes.
Correcao:
- verify forcar whitelist de algoritmos:
jwt.verify(token, publicKey, { algorithms: ['RS256'] }) - Chave privada / chave publica com nomes estritamente separados (evitar confusao em getKey)
Cenario 4: exp Nao Validado, Token Expirado Continua Sendo Aceito
Sintoma: Um servico JWT tem exp, mas a biblioteca verify por padrao ignoreExpiration: true (por compatibilidade com “tokens permanentes”), todos os tokens expirados passam. O usuario muda a senha mas o atacante usa o token antigo continua sendo utilizavel durante 30 dias.
Correcao:
- Verificar exp explicitamente:
jwt.verify(token, secret, { algorithms: ['HS256'], ignoreExpiration: false }) - Nunca depender de valores padrao
Cenario 5: Ataque de Remocao de Assinatura
Sintoma: Bug de implementacao da biblioteca verify de algum JWT: quando a assinatura esta vazia diretamente retorna payload. O atacante captura um token valido → modifica o payload → remove a assinatura → header.payload. envia, burla a verificacao de assinatura.
Correcao:
- Antes de verify verificar token.split(’.‘).length === 3 e o terceiro segmento nao esta vazio
- Sempre usar biblioteca JWT madura (dividir + verificar voce mesmo e facil que tenha bugs)
- Caso de teste:
token = "header.payload."deve ser rejeitado
Plano de Protecao 7 Dias
Dia 1: Forcar Whitelist de Algoritmo
5 minutos. Revisao de codigo verificando todas as chamadas verify JWT, garantir especificar whitelist de algoritmos:
- Node.js jsonwebtoken:
jwt.verify(token, secret, { algorithms: ['HS256'] }) - Python PyJWT:
jwt.decode(token, secret, algorithms=['HS256']) - Java java-jwt:
Jwts.parser().verifyWith(key).build().parseSignedClaims(token) - Sempre rejeitar alg=none
Efeito: Ataque alg=none + ataque de confusao HS256/RS256 completamente bloqueados.
Dia 2: JWT Secret via Variaveis de Ambiente
30 minutos. Mover todos os JWT secret / chave privada de arquivos de codigo / config para variaveis de ambiente:
- Criar
.env.example(placeholder, sem secret real, commitar) .gitignoreadicionar.env- Codigo mudar para `const JWT_SECRET=*** CI usa GitHub Actions secrets + OIDC
Efeito: Risco de vazamento de JWT secret no Git reduzido a zero.
Dia 3: Sempre Verificar exp + Expiracao Curta
1 hora. Revisao de codigo de todas as chamadas verify, garantir:
ignoreExpiration: falseespecificado explicitamente- expiracao do access token ≤ 15 minutos
- expiracao do refresh token ≤ 7 dias
- rotacao do refresh token (regenerar apos cada uso)
Efeito: Apos o vazamento do token maximo 15 minutos acessivel, nao 7 dias.
Dia 4: kid Whitelist Estrito
30 minutos. Revisao de codigo da funcao getKey, garantir:
- O valor kid deve corresponder a
^[A-Za-z0-9_-]{1,32}$ - O valor kid deve estar no conjunto de chaves conhecido
- Nao tratar kid como nome de arquivo / parametro SQL / caminho URL
- Rejeitar campos jwk / jku / x5u proprios do token (usar chave configurada no servidor)
Efeito: Ataque de injecao kid completamente bloqueado.
Dia 5: A Assinatura Deve Ser Verificada
15 minutos. Revisao de codigo de pre-checagens de verify:
- token.split(’.‘).length === 3
- Terceiro segmento (assinatura) nao vazio
- Versao da biblioteca e a ultima (sem vulnerabilidades conhecidas de remocao de assinatura)
- Caso de teste:
token = "header.payload."deve ser rejeitado
Efeito: Ataque de remocao de assinatura completamente bloqueado.
Dia 6: Mecanismo de Revogacao de refresh token
Meio dia. Implementar rotacao de refresh token + blacklist:
- Banco de dados armazena refresh tokens (associados user_id + device + estado revoked)
- Apos cada uso de refresh token: gerar novo, marcar antigo como revoked
- Detectar refresh token revogado sendo usado → revogar todos os tokens desse usuario (suspeitar token roubado)
- Ao mudar a senha: revogar todos os refresh tokens, forcar re-login
- Redis cachea estado revoked (cenarios de acesso de alta frequencia)
Efeito: Apos logout / mudanca de senha / desabilitacao de conta o token antigo e invalido imediatamente.
Dia 7: Auditoria do Payload JWT
1 hora. Revisao de codigo de todas as chamadas sign JWT, garantir que o payload so contem identificadores nao sensiveis:
user_id(UUID, nao numero derivavel)role(papel, sem expor estrutura organizacional)exp / iat / nbf(timestamps)- Nao incluir: telefone / email / cartao de identificacao / cartao bancario / hash de senha / endereco
Efeito: Mesmo se o token vazar, a PII nao sera exposta.
Decisoes de Selecao de Ferramenta
Opcao A: Servicos JWT Comerciais (Auth0 / Clerk / Firebase Auth / AWS Cognito)
Melhor para: Equipes medias-grandes / autenticacao unificada multi-produto / conformidade rigorosa (financas / saude).
Vantagens: Seguranca madura / padrao OAuth 2.0 + OIDC / rotacao de refresh token incorporada / blacklist incorporada / auditoria de conformidade. Desvantagens: Preco alto (Auth0 MAU > 1000 comeca em $240/mes), vendor lock-in, auto-hospedagem dificil.
Opcao B: Auto-implementar com Bibliotecas JWT Maduras (PyJWT / jsonwebtoken / java-jwt)
Melhor para: Individual / equipe pequena / startup / MVP.
Vantagens: Gratis / flexivel / totalmente controlavel / compativel com padrao. Desvantagens: Auto-implementar revoke / rotacao (facil de bug), precisa auto-implementar plano de protecao 7 dias, sem auditoria incorporada.
Opcao C: Decodificador JWT Piick
Melhor para: Qualquer cenario de debug / auditoria / aprendizagem.
100% local sem upload, especialmente adequado para verificar tokens suspeitos em tempo de debug / auditar payload JWT / aprender estrutura JWT:
- Decodificar header + payload (base64url decodificacao em um clique, mostrar JSON em texto plano)
- Parsear exp / iat / nbf / aud / iss / sub (mostrar contagem regressiva de expiracao, marcar vermelho ja expirado)
- Verificar existencia de assinatura + algoritmo (avisar alg=none)
- Verificacao de seguranca de kid / jku / x5u (avisar campos suspeitos)
- Nao armazena nada (decodificacao local, destruir ao fechar a pagina)
Arvore de decisao:
- Medio-grande / multi-produto / conformidade → Opcao A (Auth0 / Clerk)
- Individual / equipe pequena / MVP → Opcao B (biblioteca madura + plano de protecao 7 dias)
- Qualquer debug / auditoria → Opcao C (Piick decodificacao local)
Praticas Recomendadas
- Sempre forcar whitelist de algoritmo JWT (
algorithms: ['HS256']ou['RS256']), sempre rejeitaralg=none - Sempre verificar exp (explicito
ignoreExpiration: false), access token ≤ 15 minutos - Nunca coloque PII no payload JWT (sem telefone / email / cartao de identificacao / cartao bancario)
- Sempre colocar JWT secret em env vars + .gitignore, nunca hardcode para Git
- Sempre usar biblioteca JWT madura (PyJWT / jsonwebtoken / java-jwt), nao implementar verify voce mesmo
- Sempre usar rotacao de refresh token + blacklist, access token ≤ 15 minutos + refresh token ≤ 7 dias + rotacao
- Sempre kid whitelist de caracteres (apenas permitir
[A-Za-z0-9_-]), rejeitar campos jwk / jku / x5u proprios do token - Sempre testar ataque de remocao de assinatura:
token = "header.payload."deve ser rejeitado - Use Decodificador JWT Piick localmente decodifica tokens suspeitos verifica header / payload / exp / assinatura, nao consome tokens sem upload de log (dados 100% locais), Formatador JSON Piick embeleza estrutura JSON do payload JWT valida schema, Testador de Regex Piick escreve regex valida formato de claim JWT (iat e numero, exp e numero, sub e UUID), Codificador/Decodificador URL Piick verifica se URL de callback OAuth contem token em query string, Gerador Cron Piick gera programacao de rotacao JWT — conjunto de 5 pecas cobre todos os cenarios dev JWT online / debug / seguranca, dados 100% locais sem upload
JWT nao e criptografia e codificacao, a assinatura so pode evitar manipulacao nao pode manter segredo. A verdadeira “seguranca JWT” = forcar whitelist de algoritmo + verificar exp + sem PII + secret via env vars + kid whitelist + assinatura deve verificar + rotacao de refresh token + blacklist. Salve nos favoritos o Decodificador JWT Piick — verificacao em tempo de debug de tokens suspeitos em 1 minuto, dev diario nao se preocupa mais com vazamentos JWT.