3 min read

O que é JSON Web Token (JWT)?

O que é JSON Web Token (JWT)?

JWT

Este √© um padr√£o RFC 7519 que define uma maneira compacta e independente de passar informa√ß√Ķes entre aplica√ß√Ķes por meio de uma representa√ß√£o JSON. As informa√ß√Ķes podem ser verificadas e validadas porque s√£o assinadas com uma chave privada chamada "secret". O JWT √© comumente usado para autentica√ß√£o e autoriza√ß√£o entre aplicativos da web.

Podemos dividir o JWT em três partes: header, payload e signature, abaixo está um exemplo de um JWT.

Exemplo de JWT

Cont√©m informa√ß√Ķes espec√≠ficas sobre o algoritmo usado para criar assinaturas.
Os algoritmos mais usados s√£o HS256 (HMAC com SHA-256) ou RS256 (RSA Signature com SHA-256), segue o exemplo de header.

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload

Cont√©m as famosas "claims", toda informa√ß√£o no payload s√£o consideradas "claims", que podem definir o comportamento e as permiss√Ķes deste token, podemos ter claims adicionais, por exemplo perfil, abaixo temos o payload.

{
  "sub": "47A38F62-9357-58CF-04B7-36CE0C9CA6DF",
  "iss": "arn:will",
  "aud": "arrn:will",
  "name": "Will",
  "nbf": 1516239022,
  "iat": 1516239022,
  "exp": 7258129200,
  "user-role": "regular"
}
  • sub o assunto que o token se refere, neste caso o usu√°rio;
  • iss indica o emissor ou gerador do token;
  • aud define o destino do JWT;
  • name o nome em rela√ß√£o ao assunto, sendo assim usu√°rio;
  • iat define a data de cria√ß√£o do token no formato unix;
  • exp define a data de expira√ß√£o do token no formato unix;
  • nbf define a data de inicio da validade do token;
  • user-role √© uma claim que foi definida s√≥ para mostrar que podemos carregar qualquer informa√ß√£o dentro do JWT.

Voc√™ pode colocar qualquer informa√ß√£o dentro do JWT, mas observe que o token jwt √© convertido para Base64 e n√£o √© criptografado ūüĎĆ, essas informa√ß√Ķes devem ser p√ļblicas. Portanto, n√£o guarde a senha do usu√°rio, qualquer informa√ß√£o manipul√°vel por uma requisi√ß√£o HTTP ou qualquer outro protocolo. Vamos evitar essa vulnerabilidade. √Č meu amigo lembre-se...

Signature

A assinatura é criada usando uma chave privada ou privada com possíveis algoritmos HS256 (HMAC com SHA-256) ou RS256 (RSA com SHA-256).

Exemplo de utilização

Abaixo temos um script que gera um JWT e executa o processo de validação.

Implementação

Primeiro vamos instalar pacotes Python necess√°rios.

pip install pyjwt pytest

A implementação a seguir usa a biblioteca PyJWT para testes relacionados ao token JWT.

import pytest
import jwt
from datetime import datetime

EXPIRED_DATE = 1000000000  # September 9, 2001 1:46:40
FREEZE_DATE = datetime(2200, 1, 1, 0, 0, 0).timestamp()
ALGORITHM = "HS256"
DEFAULT_AUDIENCE = "urn:willsenadev"
JWT_SECRET = "jwt_secret"
DEFAULT_PAYLOAD = {
    "user-role": "regular",
    "issuer": "some-api",
    "aud": DEFAULT_AUDIENCE,
}


def generate_token(payload, secret):
    return jwt.encode(payload, secret, algorithm=ALGORITHM)


def validate_and_decode_token(token, secret):
    return jwt.decode(token, secret, audience=DEFAULT_AUDIENCE, algorithms=[ALGORITHM])


def decode_token(token):
    return jwt.decode(
        token, algorithms=[ALGORITHM], options={"verify_signature": False}
    )

Testes

Para n√£o perder bons h√°bitos de teste, abaixo temos testes seguindo o padr√£o pytest.


def test_generate_jwt():
    token = generate_token(payload={"user-role": "admin"}, secret=JWT_SECRET)

    assert token.startswith("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9")


def test_decode_jwt_without_validate():
    token = generate_token(payload=DEFAULT_PAYLOAD, secret=JWT_SECRET)
    payload = decode_token(token=token)

    assert payload["user-role"] == "regular"


def test_decode_jwt():
    token = generate_token(payload=DEFAULT_PAYLOAD, secret=JWT_SECRET)
    payload = validate_and_decode_token(token=token, secret=JWT_SECRET)

    assert payload["user-role"] == "regular"


def test_decode_jwt_wrong_secret():
    token = generate_token(payload=DEFAULT_PAYLOAD, secret=JWT_SECRET)

    with pytest.raises(jwt.exceptions.InvalidSignatureError):
        validate_and_decode_token(token=token, secret="wrong-secret")


def test_decode_jwt_expired():
    token = generate_token(
        payload=DEFAULT_PAYLOAD | {"exp": EXPIRED_DATE}, secret=JWT_SECRET
    )

    with pytest.raises(jwt.exceptions.ExpiredSignatureError):
        validate_and_decode_token(token=token, secret=JWT_SECRET)


def test_decode_jwt_not_accepted_yet():
    token = generate_token(
        payload=DEFAULT_PAYLOAD | {"nbf": FREEZE_DATE}, secret=JWT_SECRET
    )

    with pytest.raises(jwt.exceptions.ImmatureSignatureError):
        validate_and_decode_token(token=token, secret=JWT_SECRET)

Você deve colocar tudo em um arquivo, nomeando como jwt_example.py e validar sua implementação executando o seguinte comando:

pytest -rA jwt_example.py      
> PASSED jwt_example.py::test_generate_jwt
> PASSED jwt_example.py::test_decode_jwt_without_validate
> PASSED jwt_example.py::test_decode_jwt
> PASSED jwt_example.py::test_decode_jwt_wrong_secret
> PASSED jwt_example.py::test_decode_jwt_expired
> PASSED jwt_example.py::test_decode_jwt_not_accepted_yet

Mais referências

Se voc√™ planeja usar JWT em sua API, √© uma boa ideia verificar se o framework escolhido possui uma implementa√ß√£o no core ou adicional, exemplos de implementa√ß√Ķes para Flask e Django.

E isso é tudo!

Neste artigo falamos um pouco sobre JSON Web Tokens (JWT) tornando esse mecanismo reconhecido pelo nosso Kernel ūü߆. Se voc√™ gostou do conte√ļdo comente e compartilhe, √© r√°pido e ajuda muito.

Deus aben√ßoe seu dia ūüôŹūüŹŅ, at√© a pr√≥xima.