O que é JWT? JSON Web Tokens explicados com um exemplo prático

  1. Início
  2. Blog
  3. Desenvolvimento de software

Desenvolvimento de Software

O que é JWT? JSON Web Tokens explicados com um exemplo prático

Um JWT permite que um servidor confie em uma solicitação sem procurar nada. Construa um do zero, tente alterá-lo e observe-o falhar, depois aprenda quando os tokens vencem as sessões e como usá-los com segurança.

9 min de leitura
O que é JWT? JSON Web Tokens explicados com um exemplo prático

Principais pontos

  • Um JWT é um token compacto e assinado com três partes: cabeçalho, carga útil e assinatura.
  • A assinatura prova que um token não foi alterado, portanto o servidor pode confiar nele sem precisar consultá-lo.
  • A carga é legível por qualquer pessoa, portanto, nunca coloque segredos nela.
  • Os tokens são difíceis de revogar, portanto, mantenha-os de curta duração e verifique-os com uma biblioteca confiável.

Depois de fazer login, como um servidor sabe que cada solicitação posterior é realmente sua? Uma resposta popular é um JSON Web Token, ou JWT, geralmente pronunciado como “jot”. É um pequeno dado assinado que o cliente envia com cada solicitação, e o servidor pode verificá-lo sem tocar no banco de dados.

A maneira mais rápida de entender um JWT é construir um e depois tentar quebrá-lo. Fizemos isso usando apenas a biblioteca padrão do Python, no Python 3.13, e a saída abaixo vem dessa execução. Este código é para aprendizado. Em uma aplicação real, use uma biblioteca bem mantida, porque é fácil errar nos detalhes da verificação.

O que é um JWT?

JWT é um padrão aberto, definido na RFC 7519, para passar declarações entre duas partes como uma string compacta. Uma reivindicação é simplesmente uma declaração, como “o ID deste usuário é 42”. Como o token está assinado, o destinatário pode confirmar quem o emitiu e se ninguém o alterou.

Pense em uma pulseira de festival. A equipe no portão verifica seu ingresso uma vez e lhe dá uma banda difícil de falsificar. Depois disso, cada barraca fica apenas olhando a banda, sem necessidade de ligar para a bilheteria. Um JWT funciona da mesma maneira que uma API.

Como funciona o login JWT

  1. O usuário envia um nome de usuário e uma senha para o endpoint de login.
  2. O servidor os verifica e cria um token assinado.
  3. O cliente armazena o token.
  4. Cada solicitação posterior inclui-o, normalmente em um cabeçalho: Authorization: Bearer <token>.
  5. O servidor verifica a assinatura e a expiração e, em seguida, lê as declarações.

O principal benefício está na etapa 5. O servidor não precisa procurar uma sessão, o que é conveniente quando muitos serviços ou servidores precisam verificar o mesmo token. Se você é novo em APIs, comece com o que é uma API.

As três partes de um JWT

Um JWT parece um texto aleatório, mas consiste em três seções codificadas em Base64URL separadas por pontos. Aqui está um que geramos:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiI0MiIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzkzNTAwMDAwLCJleHAiOjE3OTM1MDA5MDB9
.7YfUDH_T-iDh8bMmUT8mmKYwOstzT8Ty--DTTAmQGWM

Adicionamos quebras de linha para facilitar a leitura. A decodificação das duas primeiras partes fornece JSON simples:

Header:  {"alg":"HS256","typ":"JWT"}
Payload: {"sub":"42","role":"user","iat":1793500000,"exp":1793500900}
Parte Contém Objetivo
Cabeçalho Tipo de token e algoritmo de assinatura Diz como verificar o token
Carga útil Reivindicações sobre o usuário ou sessão A informação real
Assinatura Um hash das duas primeiras partes, usando uma chave Prova integridade e origem

Reivindicações padrão

Reivindicar Nome Significado
substituto Assunto Sobre quem se trata o token, geralmente um ID de usuário
isso Emissor Quem criou o token
aud Público A quem se destina o token
experiência Expiração Quando o token deixa de ser válido
isso Emitido em Quando foi criado
nbf Não antes Quando começa a ser válido
jti ID do JWT Um ID exclusivo para este token

Você também pode adicionar declarações personalizadas, como role. Os tempos são carimbos de data/hora Unix, em segundos. Mantenha a carga útil pequena, pois o token viaja com cada solicitação.

Construa um você mesmo

A criação de um token envolve a codificação das duas partes JSON e, em seguida, assiná-las com um segredo usando HMAC-SHA256:

import base64, hashlib, hmac, json

SECRET = b"demo-secret-do-not-use-in-production"

def b64url(data):
    return base64.urlsafe_b64encode(data).rstrip(b"=").decode()

def sign(message):
    return b64url(hmac.new(SECRET, message.encode(), hashlib.sha256).digest())

def create_token(payload):
    header = {"alg": "HS256", "typ": "JWT"}
    parts = [
        b64url(json.dumps(header, separators=(",", ":")).encode()),
        b64url(json.dumps(payload, separators=(",", ":")).encode()),
    ]
    message = ".".join(parts)
    return message + "." + sign(message)

A verificação funciona recalculando a assinatura e comparando-a com a do token. Somente alguém com o segredo pode produzir um correspondente:

def verify_token(token, now):
    header, payload, signature = token.split(".")
    expected = sign(header + "." + payload)
    if not hmac.compare_digest(signature, expected):
        raise ValueError("bad signature")
    claims = json.loads(b64url_decode(payload))
    if claims["exp"] < now:
        raise ValueError("token expired")
    return claims

Um token válido retornou suas reivindicações conforme esperado. compare_digest é utilizado porque roda em tempo constante, o que evita vazamento de informações por diferenças de tempo.

Tente mexer com isso

Suponha que um invasor decodifique a carga útil, altere "role":"user" para "role":"admin", codifique-a novamente e mantenha a assinatura antiga. Tentamos isso, junto com outros dois ataques:

Tentativa Resultado
Mudou a função para administrador assinatura incorreta
Usou o token 1 segundo após expirar token expirou
Defina "alg":"none" e remova a assinatura assinatura incorreta

Esta última tentativa visa uma verdadeira fraqueza histórica. Algumas bibliotecas já confiaram no próprio cabeçalho do token, então um invasor poderia simplesmente declarar que nenhuma assinatura era necessária. Nosso código sempre usa um algoritmo fixo, por isso foi rejeitado. Em uma biblioteca real, sempre especifique os algoritmos que você aceita.

Assinado, não criptografado

Este é o ponto mais incompreendido sobre os JWTs. Nosso token forjado foi rejeitado, mas seu conteúdo ainda era perfeitamente legível:

{"sub":"42","role":"admin","iat":1793500000,"exp":1793500900}

Base64URL é uma codificação, não uma criptografia, e qualquer pessoa pode revertê-la sem nenhuma chave. A assinatura impede que as pessoas alterem os dados, mas não os leiam. Portanto, nunca coloque senhas, números de cartão ou dados pessoais privados em uma carga JWT. Se o conteúdo precisar ser oculto, use tokens criptografados (JWE) ou apenas mantenha os dados no servidor.

HS256 versus RS256

Aspecto HS256 RS256 ou ES256
Tipo Simétrico Assimétrico
Chaves Um segredo compartilhado Uma chave privada assina, uma chave pública verifica
Quem pode criar tokens Qualquer um que guarde o segredo Somente o detentor da chave privada
Melhor para Um serviço ou um pequeno grupo confiável Muitos serviços, terceiros, provedores de identidade

Com a assinatura assimétrica, outros serviços podem verificar tokens sem serem capazes de cunhar os seus próprios, o que limita os danos caso um deles seja comprometido.

JWT versus sessões

Os JWTs são frequentemente apresentados como um substituto moderno para sessões. Na realidade, cada um tem vantagens e desvantagens:

Aspecto Sessão do servidor JWT
Onde o estado mora No servidor No token
Pesquisa em cada solicitação Normalmente Não é necessário
Saindo ou revogando Fácil, exclua a sessão Difícil antes de expirar
Tamanho por solicitação ID pequeno Token maior (o nosso tinha 161 caracteres)
Em muitos serviços Precisa de armazenamento compartilhado Cada um pode verificá-lo diretamente
Alterando permissões Aplica-se imediatamente O token antigo permanece válido até expirar

Para um site tradicional renderizado por servidor, um cookie de sessão costuma ser mais simples e seguro. JWTs tendem a fazer mais sentido para APIs consumidas por diversos serviços ou para clientes móveis.

Dica: Não escolha JWT só porque parece sem estado. Muitos sistemas reais adicionam uma lista de bloqueios ou uma verificação de banco de dados para dar suporte ao logout, o que traz de volta a pesquisa que o JWT deveria evitar.

Onde armazenar tokens em um navegador

Localização Risco XSS Risco de CSRF Notas
armazenamento local Alto, pois os scripts podem lê-lo Baixo Simples, mas exposto a qualquer script injetado
Cookie somente http Inferior, pois os scripts não podem lê-lo Precisa de proteção Use Secure e SameSite
Variável na memória Inferior Baixo Perdido na atualização, por isso precisa de um fluxo de atualização

Muitos guias de segurança favorecem HttpOnly, Secure, SameSite cookies para aplicativos da web. Seja qual for sua escolha, sempre use HTTPS. Para enviar um token de JavaScript, consulte nosso tutorial da API JavaScript Fetch.

Atualizar tokens

A expiração curta limita o dano causado por um token roubado, mas ninguém quer fazer login a cada 15 minutos. A solução usual usa dois tokens:

  • Token de acesso: de curta duração, como minutos, e enviado com cada solicitação de API.
  • Token de atualização: tem vida mais longa, é armazenado com mais cuidado e é usado apenas para obter novos tokens de acesso.

O servidor monitora os tokens de atualização, para que possa revogá-los, o que proporciona um logout prático. Girá-los a cada uso também ajuda a detectar roubo, porque um token antigo roubado é reproduzido novamente.

Erros comuns de segurança

  • Decodificação sem verificação. Ler uma carga útil não a torna confiável. Verifique sempre a assinatura.
  • Aceitar qualquer algoritmo. Defina uma lista explícita de algoritmos permitidos.
  • Usando um segredo fraco. Segredos curtos podem ser decifrados offline. Use um valor aleatório longo e mantenha-o fora do controle de origem.
  • Ignorando a expiração. Tokens sem exp podem funcionar para sempre se roubados.
  • Não verificar iss e aud. Caso contrário, um token emitido para um serviço poderá ser aceito por outro.
  • Confiar em declarações obsoletas. Uma função dentro de um token pode ficar desatualizada até expirar.
  • Tokens de registro. Qualquer pessoa que leia seus registros poderá reutilizá-los.
  • Não testar caminhos de falha. Adicione testes para tokens expirados e modificados, bem como para tokens válidos. Nosso guia de teste de API com Postman pode ajudar.

Considerações finais

Um JWT são dados assinados nos quais um servidor pode confiar sem uma pesquisa, não um contêiner secreto e não uma atualização automática durante as sessões. Use prazos curtos, verifique tudo com uma biblioteca mantida e mantenha os dados privados fora da carga útil. Para ver por si mesmo, execute um pequeno script como o nosso, altere um caractere de um token e observe a falha na verificação.

Perguntas frequentes

Para que é usado um JWT?

JWTs são usados ​​principalmente para autenticação e autorização em APIs. Após o login, um cliente envia o token com cada solicitação e o servidor o verifica para identificar o usuário.

Um JWT é criptografado?

Geralmente não. Um JWT padrão é assinado e codificado, para que qualquer pessoa possa ler sua carga útil. A assinatura apenas impede alterações. Os tokens criptografados usam um formato relacionado chamado JWE.

Quanto tempo deve durar um JWT?

Os tokens de acesso geralmente têm vida curta, geralmente minutos em vez de dias. Combine-os com um token de atualização, para que os usuários não precisem fazer login constantemente.

Um JWT pode ser revogado?

Não por si só, pois permanece válido até expirar. A revogação requer rastreamento do lado do servidor, como uma lista de bloqueios, que remove alguns dos benefícios sem estado.

O JWT é melhor do que sessões?

Nem sempre é melhor. As sessões são mais simples de revogar e adequadas para muitos sites, enquanto os JWTs são adequados para APIs e serviços que precisam verificar a identidade de forma independente.

Continue aprendendo

Trabalhe com Stack Quora

Precisa de ajuda com testes, WordPress ou SEO?

Ajudamos as equipes a fornecer software melhor e a expandir seus sites. Conte-nos no que você está trabalhando e sugeriremos um próximo passo claro.

Continue lendo

Mais guias sobre testes, IA e desenvolvimento moderno

Gostou deste artigo? Escolha um tópico e vá direto para nossos tutoriais mais recentes.

Inteligência artificial

Explicação das alucinações de IA: por que os modelos de linguagem inventam as coisas e como reduzi-las

Explicação das alucinações de IA: o que são, por que os modelos de linguagem as produzem, tipos comuns, como reduzi-las com aterramento e instruções…

Leia o artigo →
DevOps

Variáveis de ambiente explicadas: arquivos .env, segredos e configuração bem feitos

Variáveis de ambiente explicadas com exemplos de Python que executamos: leitura e configuração, por que cada valor é uma string, arquivos .env, hera…

Leia o artigo →
Desenvolvimento de software

Explicação da limitação de taxa de API: algoritmos, cabeçalhos e tratamento de erros 429

Limitação de taxa de API explicada com uma simulação que executamos: token bucket, janela fixa, janela deslizante, 429 respostas, cabeçalhos de limi…

Leia o artigo →
Automação de testes

Zombando em Python: unittest.mock, patch e os erros que fazem os testes mentirem

Zombaria em Python com unittest.mock, testado: Mock e return_value, side_effect, patch onde um nome é usado, especificação e autospec, zombaria de d…

Leia o artigo →
Teste de software

Cobertura de código explicada: cobertura de linha versus filial e o que 100% realmente significa

Cobertura de código explicada com uma execução cobertura.py real: cobertura de linha, ramal e condição, leitura de um relatório, por que 100% de cob…

Leia o artigo →
Bancos de dados e SQL

DELETE vs TRUNCATE vs DROP em SQL: diferenças, reversão e quando usar cada um

DELETE vs TRUNCATE vs DROP explicado com SQL testado: o que cada um remove, rollback, aciona, redefinição de identidade, velocidade e como PostgreSQ…

Leia o artigo →
Bancos de dados e SQL

Exibições SQL explicadas: crie, use e evite as armadilhas, com exemplos

Visualizações SQL explicadas com consultas que executamos: criação de uma visualização, resultados ao vivo, ocultação de colunas, desempenho, visual…

Leia o artigo →
Desenvolvimento de software

Interface TypeScript vs tipo: diferenças reais, testadas com o compilador

Interface TypeScript versus tipo, verificada com o compilador real: o que ambos podem fazer, o que apenas um pode fazer, mesclagem de declarações, e…

Leia o artigo →
Desenvolvimento de software

Python *args e **kwargs explicados: funções flexíveis com exemplos claros

Python *args e **kwargs explicados com o código que executamos: empacotamento e descompactação, ordem dos parâmetros, argumentos somente de palavras…

Leia o artigo →
Desenvolvimento de software

Funções Python Lambda: sintaxe, usos reais e quando não usá-los

Funções lambda do Python explicadas com o código que executamos: sintaxe, classificação com chave, mapa e filtro, fechamentos, armadilha de ligação …

Leia o artigo →
Inteligência artificial

O que são agentes de IA? Como eles funcionam, com um loop de agente simples que você pode executar

O que são agentes de IA? Um guia simples para o loop do agente, ferramentas, memória e proteções, com um pequeno loop Python que executamos, riscos …

Leia o artigo →
DevOps

Monitoramento versus observabilidade: a verdadeira diferença, com logs, métricas e rastreamentos

Explicação do monitoramento versus observabilidade: falhas conhecidas e desconhecidas, logs, métricas e rastreamentos, um passo a passo do incidente…

Leia o artigo →
DevOps

Docker Volumes vs Bind Mounts: persista os dados do contêiner da maneira certa

Volumes Docker versus montagens de ligação explicadas: por que os dados do contêiner desaparecem, volumes nomeados, montagens de ligação, tmpfs, exe…

Leia o artigo →
Automação de testes

TDD vs BDD: principais diferenças, um recurso criado de ambas as maneiras e quando usar cada um

TDD vs BDD explicado com um recurso de desconto construído em ambos os sentidos: refatoração vermelho-verde com o código que executamos, cenários da…

Leia o artigo →
Teste de software

Teste de aceitação do usuário (UAT): processo, lista de verificação e exemplos reais

Explicação do teste de aceitação do usuário: quem o executa, como ele difere do controle de qualidade, um processo de sete etapas, um modelo de caso…

Leia o artigo →
Bancos de dados e SQL

Valores SQL NULL explicados: IS NULL, COALESCE, NULLIF e as armadilhas a serem evitadas

Valores SQL NULL explicados com consultas que executamos: lógica de três valores, IS NULL, COALESCE, NULLIF, como agregações, junções e classificaçã…

Leia o artigo →
Bancos de dados e SQL

Instrução SQL CASE WHEN: sintaxe, exemplos reais e erros comuns

SQL CASE WHEN explicado com consultas que executamos: formulários simples e pesquisados, ordem de condição, pivôs com SUM, truques COUNT, classifica…

Leia o artigo →
Desenvolvimento de software

O que é JWT? JSON Web Tokens explicados com um exemplo prático

O que é JWT? JSON Web Tokens explicados: as três partes, um token construído e adulterado no código que executamos, JWT vs sessões, armazenamento, t…

Leia o artigo →
Desenvolvimento de software

Loop de eventos JavaScript explicado: pilha de chamadas, microtarefas e temporizadores com exemplos

O loop de eventos JavaScript explicado com o código que executamos: pilha de chamadas, filas de tarefas e microtarefas, por que setTimeout 0 não é i…

Leia o artigo →
Desenvolvimento de software

Geradores Python e rendimento explicado: economize memória com exemplos reais

Geradores Python e rendimento explicados com o código que executamos: como eles pausam e reiniciam, medem economia de memória, pipelines, sequências…

Leia o artigo →
Inteligência artificial

O que são incorporações? Similaridade de vetores e cossenos explicada de forma simples

O que são incorporações? Um guia em linguagem simples para vetores, similaridade de cossenos e pesquisa semântica, com um pequeno exemplo que execut…

Leia o artigo →
DevOps

Implantação azul-verde vs canário: diferenças, compensações e como escolher

Explicação da implantação azul-verde versus canário: como cada um funciona, custo, risco e reversão, agrupamento estável de usuários que testamos, m…

Leia o artigo →
Automação de testes

Testes instáveis: o que os causa e como corrigi-los para sempre

Testes instáveis explicados com demonstrações que executamos: as principais causas, como confirmar e diagnosticar uma, soluções adequadas para tempo…

Leia o artigo →
Teste de software

Teste de carga versus teste de estresse: diferenças, métricas e exemplos k6

Teste de carga versus teste de estresse explicado: o que cada um prova, testes de pico e absorção, as métricas que importam, por que as médias engan…

Leia o artigo →
Teste de software

Caso de teste versus cenário de teste: principais diferenças, exemplos e quando usar cada um

Caso de teste vs cenário de teste explicado: definições claras, uma tabela lado a lado, um recurso de redefinição de senha retirado de cenários para…

Leia o artigo →
Bancos de dados e SQL

Otimização de consultas SQL: leia planos de execução e corrija consultas lentas, com intervalos

Otimização de consulta SQL testada em um milhão de linhas: leia planos de execução, adicione os índices corretos, corrija filtros não sargáveis, use…

Leia o artigo →
Bancos de dados e SQL

SQL UNION vs UNION ALL: diferenças, exemplos e desempenho testado

SQL UNION vs UNION ALL explicado com consultas que executamos: duplicatas, as regras que ambos seguem, um bug de dados real, desempenho medido, INTE…

Leia o artigo →
Desenvolvimento de software

Tutorial da API JavaScript Fetch: GET, POST, tratamento de erros e tempos limite

Um tutorial da API JavaScript Fetch testado em um servidor local: GET e POST, por que 404 não lança, um auxiliar reutilizável, strings de consulta, …

Leia o artigo →
Desenvolvimento de software

Manipulação de arquivos Python: leitura, gravação, CSV, JSON e pathlib com exemplos

Manipulação de arquivos Python explicada com código que executamos: modos abertos, com, leitura de arquivos grandes, CSV, JSON, pathlib, arquivos bi…

Leia o artigo →
Desenvolvimento de software

Classes e objetos Python: tutorial OOP com exemplos reais

Classes e objetos Python explicados com código que executamos: __init__, métodos, atributos de classe vs instância, herança, propriedades, métodos d…

Leia o artigo →
Inteligência artificial

O que é um modelo de linguagem grande? Como funcionam os LLMs, explicado sem exageros

O que é um modelo de linguagem grande? LLMs explicados em linguagem simples: tokens, incorporações, atenção, treinamento, temperatura e janelas de c…

Leia o artigo →
DevOps

Comandos Linux para iniciantes: o guia essencial do terminal com exemplos

Comandos Linux para iniciantes, agrupados por tarefa: navegação, arquivos, visualização de logs, grep, pipes, permissões, processos e arquivos, com …

Leia o artigo →
Automação de testes

Selenium vs Playwright: principais diferenças, código comparado e qual escolher

Selenium vs Playwright comparado: arquitetura, espera, suporte a navegador e linguagem, depuração, o mesmo teste em ambas as ferramentas, conselhos …

Leia o artigo →
Teste de software

Particionamento de equivalência: técnica de design de teste explicada com exemplos resolvidos

Explicação do particionamento de equivalência: como encontrar partições válidas e inválidas, exemplos resolvidos para idades, senhas e cupons, teste…

Leia o artigo →
Teste de software

Gravidade vs Prioridade em Testes de Software: Diferenças, Matriz e Exemplos Reais

Explicação da gravidade versus prioridade em testes de software: definições claras, uma matriz de quatro vias com exemplos, escalas de nível, quem d…

Leia o artigo →
Bancos de dados e SQL

Tutorial de subconsultas SQL: tipos, subconsultas correlacionadas e EXISTS com exemplos

Um tutorial de subconsultas SQL com consultas que executamos: subconsultas escalares, IN, FROM e SELECT, subconsultas correlacionadas, EXISTS, a arm…

Leia o artigo →
Bancos de dados e SQL

Transações SQL e ACID explicados: COMMIT, ROLLBACK e níveis de isolamento

Transações SQL e ACID explicadas com uma transferência bancária que executamos: COMMIT, ROLLBACK, savepoints, locks, níveis de isolamento, leituras …

Leia o artigo →
Desenvolvimento de software

Git merge vs rebase: diferenças, exemplos e quando usar cada um

Git merge vs rebase explicado com saída real do log, uma tabela comparativa, a regra de ouro do rebase e um fluxo de trabalho seguro para equipes.

Leia o artigo →
Desenvolvimento de software

List comprehension em Python: sintaxe, exemplos e quando evitar

List comprehension em Python explicada: sintaxe, filtros, if-else, laços aninhados, tempos medidos e quando um laço for comum é a melhor escolha.

Leia o artigo →
Bancos de dados e SQL

SQL JOIN explicado com exemplos (Inner, Left, Right, Full)

Entenda os joins SQL passo a passo com tabelas e consultas de exemplo: INNER, LEFT, RIGHT, FULL, CROSS e SELF, além de erros comuns e dicas de desem…

Leia o artigo →