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.
Header
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.
- jwt.io neste site você pode manipular seu JWT, ótima ferramenta para depuração e estudos mantida pela Auth0
- JSON Web Tokens Article
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.
Time for feedback!