Nesta página

Por que você não deve colar JWTs no jwt.io (e o que usar no lugar)

Um token de produção aparece no seu terminal. Você precisa saber quem o emitiu, quando expira e quais claims ele carrega — rápido. Então você faz o que a maioria dos desenvolvedores faz: abre o jwt.io, cola o token e lê o payload decodificado.

Pare. Esse JWT é uma credencial. O site no qual você acabou de colar é operado por terceiros, com um histórico de analytics adicionados silenciosamente e uma reescrita em andamento motivada pelas próprias preocupações de privacidade dos seus mantenedores. Existe uma resposta melhor, e a busca que provavelmente trouxe você até aqui — “alternativa privada ao jwt.io” — tem uma resposta de verdade.

Este guia percorre o modelo de ameaça real, o que a própria equipe do jwt.io reconheceu publicamente e como verificar se um depurador JWT nunca envia seu token a lugar algum. Se preferir pular a explicação e decodificar um token agora mesmo no seu navegador, o JWT Decoder é totalmente client-side — abra-o, desconecte-se da internet e veja que ele continua funcionando.

TL;DR: o jwt.io é seguro?

Resposta curta: a página inicial do jwt.io avisa você mesma. O texto de aviso, em essência, diz: “JWTs são credenciais — tenha cuidado onde você os cola.” Esse aviso está correto e se aplica ao jwt.io tanto quanto a qualquer outra ferramenta online.

Para tokens de demonstração não sensíveis, o jwt.io serve. Para qualquer coisa de um ambiente real — produção, staging, sandbox, integração com parceiros — assuma o padrão mais seguro: decodifique localmente. O resto deste artigo é o porquê e o como.

O que realmente acontece quando você cola um JWT em um decodificador online

Um JWT (JSON Web Token) é composto por três segmentos codificados em Base64URL e unidos por pontos: um header, um payload e uma assinatura. O header e o payload não são criptografados; estão apenas codificados. Qualquer um que tenha o token pode ler seu conteúdo — incluindo qualquer serviço que o receba, mesmo que seja “apenas para decodificá-lo no client-side”.

Várias coisas podem acontecer entre você apertar Cmd-V e ver as claims decodificadas:

  • Histórico do navegador. Muitas ferramentas, historicamente, passavam o token na query string da URL, o que faz com que ele acabe no histórico do navegador, em referrers de abas pai e em qualquer backend de histórico sincronizado (Chrome Sync, Firefox Sync, perfis do Edge).
  • Logs de servidor. Mesmo páginas que decodificam em JavaScript ainda fazem requisições para analytics, fontes e scripts de anúncio. Se o token estiver na URL, ele aparece nos cabeçalhos Referer enviados a esses terceiros.
  • SDKs de telemetria. Até setembro de 2019, o jwt.io enviava métricas da página apesar de anunciar operação somente client-side, como documentado pelo engenheiro Jamie Tanna (Capital One Open Banking). “Client-side” é uma afirmação, não uma auditoria.
  • Mudanças futuras de código. Um site que é client-side hoje pode receber uma mudança server-side amanhã. Como colocou um comentarista bastante citado no Hacker News: “Se você criar o hábito de usar essas ferramentas, uma delas eventualmente será comprometida. Seja por um ataque técnico, pressão financeira, compra por uma entidade imoral ou um funcionário insatisfeito em algum ponto do caminho.”

Nada disso requer má-fé. Basta que alguém, em algum lugar, entre seu teclado e seus olhos, tenha uma cópia do seu token por tempo suficiente para usá-lo de forma indevida.

O modelo de ameaça real

A primeira objeção é sempre a mesma: “Mas o token expira em 15 minutos — qual é o pior que pode acontecer?” Várias coisas, na verdade.

Replay dentro da janela de expiração. Quinze minutos são tempo de sobra para um script monitorando um pipeline de analytics, um arquivo de log vazado ou um cabeçalho referrer pegar o token e chamar sua API se passando por você. Se o token for um refresh token (que pode ser válido por dias ou semanas), a janela é muito maior.

Claims são um mapa do tesouro. Um payload típico inclui o ID do usuário (sub), ID do tenant, lista de papéis, audience (aud), issuer (iss) e frequentemente claims customizadas como e-mail, flags internas ou direitos de funcionalidade. Mesmo um JWT expirado diz a um atacante exatamente qual usuário visar, qual API atingir e como é a escalação de privilégios na sua empresa.

Tokens fora de produção vazam segredos com forma de produção. JWTs de sandbox de Open Banking e tokens de integração com parceiros frequentemente contêm fingerprints de certificados, key IDs e URLs de audience que mapeiam diretamente para a infraestrutura de produção. Jamie Tanna descreveu ter sido “queimado várias vezes” por colegas colando JWTs fora de produção e certificados de sandbox de Open Banking no jwt.io.

O dano de compliance independe de impacto. Se sua empresa está sujeita a SOC 2, ISO 27001, PCI-DSS ou qualquer regra próxima da HIPAA, colar uma credencial em um serviço de terceiros é reportável independentemente de algo ter sido de fato explorado. O achado da auditoria é o incidente.

Bugs no manuseio de JWT continuam aparecendo. A CVE-2026-29000, um bypass de autenticação no JwtAuthenticator do pac4j, foi divulgada no início deste ano. Bugs de validação de token não são um problema de 2018; depurar JWTs é exatamente quando os desenvolvedores recorrem a ferramentas online, e exatamente quando tokens vazados são mais úteis para um atacante observando a mesma biblioteca.

O que os próprios mantenedores do jwt.io disseram

O argumento mais forte contra colar tokens no jwt.io vem do próprio jwt.io.

Na issue #700 do GitHub, “The Future of JWT.io”, aberta em 19 de julho de 2024, um engenheiro de DevRel da Okta/Auth0 escreveu — textualmente — que “passar um token para o site via parâmetros de query da URL gerou preocupações sobre a privacidade do token.” A issue detalha uma reescrita planejada que troca os parâmetros de query da URL por fragmentos da URL, separa decodificação/codificação/verificação em widgets distintos e para de carregar tokens automaticamente da URL no carregamento da página.

Essa é a equipe que administra o jwt.io comprometendo-se publicamente com uma reformulação porque o tratamento existente não é suficientemente privado. No momento desta redação, partes da reformulação foram lançadas e partes não. O status exato é irrelevante para você: o ponto é que a régua de privacidade do próprio operador é mais alta que a do site legado, e você não tem como saber com confiabilidade qual versão um determinado visitante está usando em um determinado dia.

Separadamente, o The State of JWT Libraries on JWT.io (28 de março de 2025) da PentesterLab descobriu que a lista curada de bibliotecas do jwt.io ainda recomenda repositórios arquivados em 2018, bibliotecas atualizadas pela última vez em 2015 e pelo menos uma implementação que suporta HMAC-MD5 (um algoritmo que não existe na especificação JWT). Uma biblioteca da lista extrai o valor de alg por regex em vez de fazer parsing de JSON; outra assina com “uma string aleatória de comprimento aleatório e o payload como segredo.” Louis Nyffenegger, fundador da PentesterLab, resume: “Os desenvolvedores podem, sem saber, escolher bibliotecas inseguras ou abandonadas.”

O catálogo de bibliotecas não é o mesmo problema que a privacidade do token, mas aponta na mesma direção: a propriedade “popular e conveniente” está fazendo muito trabalho injustificado no seu modelo de confiança.

O que “decodificador JWT client-side” realmente significa

Um decodificador genuinamente client-side faz três coisas:

  1. Carrega o código por HTTPS uma vez e depois roda inteiramente na sua aba do navegador.
  2. Realiza a decodificação em JavaScript usando atob() (ou um helper de Base64URL) e JSON.parse() nos segmentos de header e payload.
  3. Opcionalmente verifica assinaturas usando a Web Crypto API, a mesma primitiva auditada que protege seus handshakes TLS.

Sem fetch, sem XHR, sem navigator.sendBeacon, sem ping de analytics levando o token. Os bytes do token nunca saem da memória da aba.

Esse não é o padrão. Essa é uma propriedade que uma ferramenta tem ou não tem, e que você mesmo pode verificar em menos de um minuto.

Como verificar se uma ferramenta JWT é realmente client-side (receita de 60 segundos)

Esta é a habilidade mais útil deste artigo. Execute-a em toda ferramenta que toque em credenciais, incluindo as do remove.sh.

Método 1: o teste do modo avião

  1. Abra a ferramenta em uma nova aba.
  2. Espere a página carregar completamente.
  3. Desabilite o Wi-Fi ou ative o modo avião.
  4. Cole um token e decodifique.

Se o header e o payload decodificados aparecerem, a ferramenta está fazendo o trabalho localmente. Se você ver um spinner ou um erro, a ferramenta está fazendo uma chamada ao servidor — provavelmente com o seu token no corpo da requisição. Esta é a verificação mais rápida e definitiva.

Método 2: a auditoria de rede pelo DevTools

  1. Abra o DevTools (F12 ou Cmd+Option+I).
  2. Mude para a aba Network.
  3. Filtre por Fetch/XHR.
  4. Clique em Clear (o ícone de proibição) e cole seu token.

Um decodificador client-side mostrará zero requisições Fetch/XHR durante a decodificação. Se você vir uma requisição, clique nela e inspecione a aba Payload — seu token pode estar no corpo ou na query string da requisição. Mesmo que não esteja, a ferramenta está acessando a rede a cada tecla digitada, o que já é suficiente para descartá-la em trabalhos sensíveis.

Método 3: leia a barra de URL

Se a ferramenta coloca o token diretamente na URL — ?token=eyJhbG... — esse token agora está no histórico do seu navegador, no histórico do shell se você copiou a URL, no cabeçalho Referer enviado para todo script de analytics da próxima página que você visitar, e em qualquer gerenciador de clipboard que você use. Ferramentas que usam fragmentos de URL (#token=...) são melhores, porque fragmentos não são enviados aos servidores, mas parâmetros de query são desclassificadores imediatos.

Experimente você mesmo: abra o JWT Decoder no remove.sh e execute as três verificações. O painel Network permanece vazio após o carregamento da página, a URL nunca contém seu token e a página funciona em um avião. Isso é uma propriedade verificável, não uma alegação de marketing.

Uma alternativa privada ao jwt.io: decodifique no seu navegador

Se você chegou até aqui, a recomendação não é surpresa: use um decodificador que você possa verificar e, em seguida, verifique-o.

O JWT Decoder do remove.sh é construído com as mesmas primitivas que este artigo descreve. Ele usa atob() para os segmentos Base64URL, JSON.parse() para o header e o payload, e a Web Crypto API para verificação de assinaturas HMAC (HS256/HS384/HS512). Os tokens nunca são serializados na URL. Não há SDK de analytics lendo o campo de entrada. A ferramenta informa o status de expiração comparando a claim exp com o seu relógio local e rotula as claims registradas (iss, sub, aud, iat, nbf, jti) para que você não tenha que decorá-las.

O que ela não faz, hoje, é verificar assinaturas RSA ou ECDSA (RS256/ES256). Para assinaturas assimétricas, você tem duas opções razoáveis, ambas cobertas na próxima seção.

Se o seu token está envolto em Authorization: Bearer eyJhbG..., cole o conteúdo inteiro — o decodificador remove o prefixo Bearer automaticamente. Se você só tem os segmentos codificados em Base64 e quer inspecioná-los crus, o Base64 Encoder & Decoder decodifica segmentos individuais sem tentar interpretá-los como um JWT, o que é útil quando você suspeita de um token malformado.

Verificando assinaturas sem expor seu segredo

Decodificar diz a você o que um token afirma. A verificação diz se você deve confiar nele. As duas operações não são iguais e têm implicações de privacidade diferentes.

HMAC (HS256/HS384/HS512)

A verificação HMAC requer o segredo compartilhado. Esse é o caso perigoso: um segredo vazado significa que qualquer um pode emitir tokens válidos para o seu serviço. Nunca cole um segredo HMAC em uma ferramenta online da qual você não consiga verificar que é local.

O JWT Decoder do remove.sh verifica assinaturas HMAC com a Web Crypto API. O segredo permanece na memória da sua aba e nunca é serializado para a rede. Você pode confirmar isso executando o teste do modo avião com tanto o token quanto o segredo preenchidos — a verificação ainda é concluída.

Se você quer uma garantia mais forte do que mesmo uma aba de navegador auditada, recorra à receita local de openssl abaixo para recalcular o HMAC a partir da porção header-payload e compará-lo com o segmento de assinatura você mesmo.

RSA / ECDSA (RS256, RS384, RS512, ES256, ES384, ES512)

A verificação assimétrica precisa apenas de uma chave pública, que por definição não é secreta. Esse é o caso fácil para ferramentas online — os dados que circulam não são sensíveis por si só. A única coisa que você deve proteger é o token, que contém as mesmas claims independentemente do algoritmo.

Até que o remove.sh entregue verificação RSA/ECDSA no decodificador, a opção local mais limpa é o step crypto:

step crypto jwt verify \
  --jwks https://your-issuer.example.com/.well-known/jwks.json \
  --iss https://your-issuer.example.com \
  --aud your-audience < token.txt

Ou com openssl e uma chave pública em formato PEM:

# Extract the signed portion (header.payload)
SIGNED=$(cut -d. -f1,2 token.txt)

# Extract the signature, decode Base64URL
cut -d. -f3 token.txt | tr '_-' '/+' | base64 -d > sig.bin

# Verify with openssl
echo -n "$SIGNED" | openssl dgst -sha256 -verify pubkey.pem -signature sig.bin

Ambos funcionam offline. Ambos permitem verificar um token sem nunca colá-lo em um site.

Decodificando um JWT localmente com a CLI

Para inspeções pontuais longe de qualquer navegador, dois one-liners cobrem a maioria dos casos.

Imprimir o header de forma legível:

cut -d. -f1 token.txt | tr '_-' '/+' | base64 -d 2>/dev/null | jq .

Imprimir o payload de forma legível:

cut -d. -f2 token.txt | tr '_-' '/+' | base64 -d 2>/dev/null | jq .

A etapa tr '_-' '/+' converte Base64URL para Base64 padrão, que é o que a maioria dos decodificadores espera. O 2>/dev/null engole o aviso base64: invalid input que aparece quando o segmento não está com padding — o jq ainda imprimirá o JSON corretamente.

Se você não tem o jq, o JSON Formatter no remove.sh formata a saída de qualquer um dos comandos no seu navegador sem enviá-la a lugar algum. Direcione para o seu clipboard com pbcopy (macOS) ou xclip -sel clip (Linux) e cole.

Como compartilhar um JWT com segurança em um relatório de bug

Uma razão comum pela qual desenvolvedores recorrem ao jwt.io não é depuração — é colar um payload decodificado em uma thread do Slack ou em um ticket para um colega ver as claims. Existe uma receita mais segura.

  1. Decodifique o token localmente com um dos métodos acima.
  2. Copie apenas o JSON decodificado — nunca a forma codificada eyJhbG.... A forma codificada é a credencial; o JSON decodificado é apenas dado.
  3. Redija claims identificadoras antes de compartilhar: substitua sub, email, name, IDs customizados de usuário e IDs de tenant por valores de placeholder (sub: "user-redacted").
  4. Descarte o segmento de assinatura. Ele não pode ser reconstruído a partir do header e do payload sem o segredo ou a chave privada, o que significa que o JSON redigido não é mais uma credencial utilizável.
  5. Para fixtures de teste, gere um token novo assinado com um segredo descartável. O que importa para reproduzir o bug é a forma, não os valores.

Se um colega precisa confirmar “sim, este é o mesmo token que estou vendo aqui” sem que nenhum de vocês compartilhe o token em si, cole o JWT codificado no Hash Generator no remove.sh e troquem o fingerprint SHA-256 no lugar. Mesmo fingerprint significa mesmo token; o fingerprint não revela nada sobre as claims ou a assinatura.

Essa abordagem transforma uma troca de credenciais em uma troca de dados, que é o que sua política de segurança realmente quer.

Perguntas frequentes

O jwt.io é open source?

O código frontend do site está publicado no GitHub, mas “open source” não diz a você o que está sendo executado no jwt.io hoje. Como Jamie Tanna observou, “não temos ideia se o código-fonte… está realmente sendo usado” no site em produção. A verificabilidade — uma aba Network que permanece vazia — é um sinal mais forte do que um repositório público.

O jwt.io já vazou tokens?

Não há divulgação pública de um incidente de vazamento de token. Há um reconhecimento público dos mantenedores (GitHub #700) de que o tratamento legado de query da URL gerou preocupações de privacidade sérias o suficiente para motivar uma reescrita. A ausência de um incidente conhecido não é o mesmo que ausência de risco.

Posso hospedar o jwt.io eu mesmo?

Sim, o código-fonte está disponível, mas auto-hospedar só resolve o problema de confiança na rede se você de fato auditar o build e servi-lo a partir de uma infraestrutura que você controla. Para a maioria das equipes, uma ferramenta client-side já verificada dá menos trabalho e menos risco do que manter um fork.

Decodificar um JWT requer o segredo?

Não. Decodificar o header e o payload requer apenas decodificação Base64URL e parsing de JSON — ambas operações puramente locais. O segredo só é necessário para verificar a assinatura, que é uma etapa separada. Qualquer ferramenta que peça seu segredo apenas para exibir as claims decodificadas está fazendo algo errado.

Por que meu token aparece como expirado mesmo recém-emitido?

A claim exp é comparada com o relógio local. Decodificadores rodando em um navegador usam o relógio do seu sistema; ferramentas de CLI usam o relógio do host. Um relógio fora de sincronia — comum em VMs e runners de CI — fará tokens válidos parecerem expirados e vice-versa. Sincronize seu relógio (sudo sntp -sS time.apple.com ou sudo ntpdate pool.ntp.org) e tente novamente.

É realmente seguro colar um token em uma ferramenta que você verificou ser client-side?

Sim, com uma ressalva. Uma ferramenta que é client-side hoje pode não ser amanhã. A verificação da aba Network precisa ser repetida quando você confiar a uma ferramenta um token particularmente sensível, especialmente após um longo intervalo. Adicionar a ferramenta aos favoritos, ou usar uma extensão de navegador que avise sobre requisições de saída de uma origem específica, torna isso mais barato.

Como isso se relaciona com a postura de privacidade mais ampla do remove.sh?

A mesma arquitetura se aplica a toda ferramenta de desenvolvedor do site. O argumento mais longo está em Client-Side Developer Tools: The Privacy-First Approach, que cobre formatadores de JSON, geradores de hash, decodificadores Base64 e a Web Crypto API em detalhe.

Conclusão

O jwt.io é uma conveniência popular que lida com uma classe de dados — credenciais — para a qual “conveniência popular” não é um modelo de confiança suficiente. Os próprios mantenedores escreveram, em público, que o site legado tem problemas de privacidade sérios o bastante para justificar um redesenho. O substituto não é o redesenho do jwt.io nem qualquer concorrente único; é um hábito.

O hábito é: antes que qualquer ferramenta veja um token, execute o teste do modo avião. Se funcionar offline, é local. Se não, encontre uma que funcione — ou recorra a um one-liner de CLI.

O JWT Decoder no remove.sh foi construído para passar nesse teste. Abra-o, desabilite sua rede e decodifique um token. Se ainda funcionar — e vai funcionar — você acabou de verificar, com seus próprios olhos, que nenhum terceiro jamais verá esse JWT.

Essa é a resposta para “alternativa privada ao jwt.io”. Não uma marca diferente. Uma propriedade verificável.