JSON Web Tokens: explicado

Luis Felipe Zaguini
Training Center
Published in
5 min readFeb 16, 2018

O ano é 2018. Em uma era em que performance é tudo (principalmente custo), desenvolvedores buscam economizar cada bit transferido na grande rede. Mais do que nunca as APIs REST estão voando (e suas alternativas, como o GraphQL), e, nessa necessidade incessante de performance ao máximo, formas de transmitir a menor quantidade de dados possível também precisam ser seguras o suficiente para que hajam valor.

Mas como podemos fazer isso? Como podemos transmitir mensagens entre duas partes de maneira segura, rápida e leve? Aí que surgem os JSON Web Tokens!

O que são JSON Web Tokens?

O JWT (se pronuncia "jót") é nada além de uma longa string — é sério. Essa string se "autocompõe", ou seja, ela tem toda a informação necessária nela mesma. Isso quer dizer que JWTs são capazes de transmitir informações sobre si mesmo (explico mais sobre ali embaixo).

Um JWT, por ser uma string, pode ser facilmente transportado. Tipicamente, um JSON Web Token é inserido dentro de um cabeçalho numa requisição HTTP para autenticação em uma API, por exemplo.

A anatomia de um JWT

JSON Web Tokens são absurdamente simples. Como disse acima, é apenas uma string grande unida em três partes e separadas por pontos (".").

aaaaa.bbb.ccc

Tanto a parte dos "a"s quanto a parte dos "b"s são nada além de objetos JSON codificados em base 64, enquanto a parte dos "c"s é um hash computado a partir da concatenação das duas strings base 64 unidas por um ponto ("."). Esse hash compõe a parte final do JWT e serve para verificação da integridade do token.

Um JWT, com suas partes em base 64 já decodificadas para fins de explicação, é formado por um:

Header (a parte em vermelho, representa o "a"): é um objeto JSON que contém informações prévias sobre o token, como o algoritmo ("ALGoritmo") utilizado para a computação da assinatura, sendo o HS256 o mais comum; o tipo e algumas outras claims, que são os pedaços de informação transmitidos dentro do JWT.

Payload (a parte em azul, representando o "b"): são as informações que o JWT carrega, tipicamente a data de expiração do token ("EXPiration date"), quem gerou aquele token ("ISSuer"), quando ("Instanciated AT"), quem deve consumi-lo ("AUDience"), e o que mais for necessário entre as partes — como por exemplo um ID de usuário.

Assinatura (a parte verde, representa o "c"): como explicado acima, é uma hash gerada a partir da concatenação do header e do payload, codificados em base 64 e unidos por um ponto (".").

Como posso tirar proveito dos JWTs e como eles são seguros?

Todo JWT tem sua assinatura computada. Lembrando do fato que ele se "autocompõe", isso quer dizer que ele leva junto com os dados a sua assinatura, para que quem receba esse JWT possa comprovar sua integridade.

Explico: por se tratar de uma string, qualquer pessoa poderia decodificar o base 64, modificar as informações como quiser, codificar novamente e passar a string em uma requisição qualquer e obter sucesso, certo?

Errado! Qualquer alteração no header ou no payload geraria um hash diferente do que o que está embutido no token, então na hora da validação, quem está lidando com o JWT perceberia que aquele token não é confiável, o descartando e parando com o processamento imediatamente!

Tome muito cuidado! Os tokens serem íntegros não o tornam indecifráveis. No fim das contas, é apenas puro base 64. Jamais passe dados sensíveis, como senhas, CPFs e outros dados que deem sopa aos crackers de plantão.

Existem formas de encriptar JWTs, mas como esse é apenas um artigo introdutório, não abordarei.

Achei maravilhoso! Como posso implementar?

Para nossa sorte, a maioria das linguagens de programação tem bibliotecas que implementam o padrão JWT. Pela simplicidade, escolhi Python. Mãos na massa!

A biblioteca mais famosa (e mais simples) em Python é, com certeza, pyjwt, criada e mantida por José Padilla. Instale ela localmente (preferencialmente via PIP) e a importe.

Vamos supor que temos uma aplicação back end que autentica os usuários e tem endpoints com a tal camada de autenticação no topo. Na hora de autenticar, é gerado um token com validade de uma hora. Ou seja, uma hora e um segundo após gerado, caso tentemos consumir qualquer recurso da API com o token, deveremos negar a requisição.

Para autenticar um usuário, precisamos gerar um token. Isso é feito de maneira muito simples:

Primeiramente importamos a biblioteca para trabalharmos com JWT. Em seguida, importamos o método time da biblioteca de mesmo nome para gerarmos um timestamp.

Esse timestamp, em segundos, é absoluto a partir de 1970 e será passado como valor da claim exp, que serve para dizer, em qual instante, o token deve ser desconsiderado — em nosso caso, uma hora após sua geração.

No nosso payload, passamos a tal data de expiração e também uma user id (uid), clarificando qual usuário quer consumir nossos recursos. Por convenção, as claims de um JWT são escritas com três letras minúsculas.

Como estamos usando o algoritmo HS256, precisamos passar um segredo para geração do nosso hash. Ele está definido na linha 4 e é o segundo parâmetro do método encode.

Pronto! Você gerou seu primeiro JSON Web Token! Pode incluí-lo na resposta da sua requisição de login, por exemplo.

Certo. E agora?

Agora, num cenário simples, você precisa esperá-lo numa requisição à um recurso do seu aplicativo back end, tipicamente num cabeçalho. Com o JWT em mãos, é hora de validá-lo!

Temos nossa biblioteca em mãos e o nosso segredo, para verificarmos a autenticidade do token em questão. Pois bem, recuperamos nosso JWT do header de authorization e tentamos decodificá-lo. Veja que a biblioteca já faz todo o trabalho sujo para você: desde a checagem do tempo de expiração até ao formato do token e o segredo utilizado para computar a hash!

Sensacional, não é? É só o começo. JSON Web Tokens são incríveis e certamente não devem sair de cena nos próximos anos. Caso você queira saber mais à fundo como nossos queridos JWTs funcionam, recomendo que leia a documentação do PyJWT no GitHub, que é precisa e objetiva.

Quaisquer dúvidas ou feedbacks, faça proveito da caixa de respostas abaixo. Forte abraço!

--

--