NGINX Plus versão 10 introduziu suporte à transferência da autenticação de serviços web e de API para JSON Web Tokens (JWTs, pronunciados “jots”). Desde o lançamento da R10, continuamos ampliando as funcionalidades a cada nova versão.
A partir do NGINX Plus R14, o NGINX Plus oferece suporte a JWTs que contêm declarações aninhadas e dados de matriz. Quando usado em um cenário de gateway de API, o NGINX Plus pode usar JWTs para autenticar clientes que solicitam conexões com serviços de back-end e destinos de API.
Ocasionalmente, pedem que eu forneça uma configuração básica que use o NGINX Plus para autenticar JWTs e, em seguida, tome decisões mais avançadas de balanceamento de carga com base nas informações contidas nesses JWTs. A solução mais simples é permitir o acesso a um serviço se a autenticação for bem-sucedida e bloquear ou redirecionar a conexão em caso de falha.
O passo a passo apresentado neste post é uma prova de conceito completa de autenticação JWT e roteamento baseado em conteúdo usando o NGINX Plus. Para abranger a maior variedade possível de cenários e reduzir a necessidade de conhecimentos prévios ou experiência com JWTs, criei um passo a passo de “JWT 101”, que permite implantar essa solução (com exemplos e informações de contexto) sem nenhum conhecimento prévio sobre JWTs.
Se você já tem experiência com JWT ou já utiliza JWTs em seu ambiente, pode pular as duas primeiras seções e adaptar os trechos de configuração do NGINX Plus fornecidos ao seu ambiente para começar a tomar decisões avançadas de balanceamento de carga com base nos dados das declarações dos seus JWTs.
Pré-requisitos
Este documento pressupõe uma nova instalação do NGINX Plus, com os arquivos de configuração padrão nos seguintes locais:
- /etc/nginx/nginx.conf
- /etc/nginx/conf.d/default.conf
Para obter mais informações sobre como instalar e começar a usar o NGINX Plus, consulte o Guia de Administração do NGINX Plus.
Todos os comandos da CLI pressupõem privilégios de root, portanto, usuários que não sejam root precisam ter permissões de sudo em seu ambiente.
Para obter mais informações de contexto e conhecer outros casos de uso de JWTs com o NGINX Plus, consulte os links a seguir:
- Módulo JWT — documentação de referência
- Autenticação de clientes de API com JWTs e NGINX Plus
- Autenticação de usuários em aplicações existentes com OpenID Connect e NGINX Plus
Criando um JWT e uma chave de assinatura associada
As instruções abaixo orientam você na criação de um JWT do zero, com dados de payload específicos do nosso exemplo, para ilustrar como configurar o NGINX Plus para o processamento básico de declarações JWT. Se você usar um JWT existente em vez do JWT de exemplo, verifique se o arquivo de “segredos” contém a string codificada em Base64URL correspondente à chave de assinatura usada para criar o JWT. Provavelmente, você também precisará modificar as declarações no payload do JWT.
Observação: Independentemente de como você gerar seu JWT, é necessário usar a codificação Base64URL, que processa corretamente o preenchimento (feito com o caractere =), bem como outros caracteres incompatíveis com HTTP normalmente usados na codificação Base64. Muitas ferramentas fazem isso automaticamente, mas codificadores Base64 manuais baseados em CLI e algumas ferramentas de criação de JWT não. Para obter mais informações sobre a codificação Base64URL, consulte Codificação Base64URL de Brock Allen e a RFC 4648.
Neste exemplo, estamos usando a interface gráfica do jwt.io (que realiza corretamente a codificação Base64URL) para criar um JWT HS256 simétrico. A captura de tela a seguir mostra a aparência da interface gráfica depois que você insere os valores especificados nas instruções abaixo e a assinatura é verificada.

Na interface gráfica do jwt.io, gere um JWT HS256 verificando ou inserindo os valores indicados nos campos da coluna Decoded à direita:
- Verifique se o seguinte valor padrão aparece no campo HEADER e, se necessário, modifique o conteúdo para que corresponda:
{ "alg": "HS256",
"typ": "JWT"
}- No campo VERIFY SIGNATURE, substitua o valor na caixa (por padrão,
secret) pornginx123. (Faça essa alteração antes de inserir os dados no campo PAYLOAD para evitar um problema que ocorre se você inverter a ordem das duas etapas.) - Substitua o conteúdo do campo PAYLOAD pelo seguinte:
{ "exp": 1545091200,
"name": "Create New User",
"sub": "cuser",
"gname": "wheel",
"guid": "10",
"fullName": "John Doe",
"uname": "jdoe",
"uid": "222",
"sudo": true,
"dept": "IT",
"url": "http://secure.example.com"
}- Observação: A declaração
expdefine a data e a hora de expiração do JWT, representando-as como um horário da época UNIX (o número de segundos desde a meia-noite UTC de 1º de janeiro de 1970). O valor de exemplo representa a meia-noite UTC de 18 de dezembro de 2018. Para ajustar a data de expiração, altere o horário da época. - Verifique se a barra abaixo dos campos está azul e exibe a mensagem Assinatura verificada.
- Copie o valor da coluna Codificado à esquerda para um arquivo ou buffer. Esse é o texto completo do JWT que o usuário jdoe precisa apresentar para acessar http://secure.example.com, e nós o usaremos em nossos testes abaixo. Para fins de exibição, mostramos o JWT com quebras de linha aqui, mas ele deve ser apresentado ao NGINX Plus como uma string de uma única linha.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOi
JDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkI
joiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIy
Iiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGx
lLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4
No host do NGINX Plus, siga estas etapas para criar o arquivo de chave que o NGINX Plus usa para verificar JWTs assinados com nginx123:
- Execute este comando para gerar a string codificada em Base64URL correspondente à string de assinatura. (Os comandos
trfazem as substituições de caracteres necessárias para a codificação Base64URL.)
# echo -n nginx123 | base64 | tr '+/' '-_' | tr -d '='bmdpbngxMjM- No diretório /etc/nginx/ crie o arquivo de chave chamado api_secret.jwk, que será usado pelo NGINX Plus para verificar assinaturas JWT. Insira o conteúdo a seguir. O valor no campo
ké a forma codificada em Base64URL denginx123, que geramos na etapa anterior.
{"keys": [{
"k":"bmdpbngxMjM",
"kty":"oct"
}]
}Configurando o NGINX Plus para processar JWTs
As instruções desta seção configuram o NGINX Plus para validar o JWT incluído em uma solicitação e apresentar um recurso protegido caso o cliente esteja autorizado (em vez da página padrão exibida para clientes não autorizados). Também definimos um novo formato de log que registra informações relacionadas ao JWT.
Configurando a validação de JWT e o roteamento baseado em conteúdo
Nestas instruções, seguimos a prática recomendada padrão de renomear o arquivo de configuração default.conf para que o NGINX Plus não o leia e de criar uma nova configuração especificamente para testes. Isso permite restaurar facilmente a configuração padrão quando você terminar os testes ou se ocorrer algum problema durante eles.
- Renomeie default.conf:
# mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak- Crie um novo arquivo de configuração chamado jwt-test.conf em /etc/nginx/conf.d/, com o conteúdo a seguir. Essas configurações definem o registro de logs específico para JWT, a validação de JWT e o roteamento baseado em conteúdo (uma análise completa é apresentada após o trecho de código).
server {
listen 80;
access_log /var/log/nginx/host.access.log jwt;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
# JWT validation
auth_jwt "JWT Test Realm" token=$arg_myjwt;
auth_jwt_key_file /etc/nginx/api_secret.jwk;
error_log /var/log/nginx/host.jwt.error.log debug;
if ( $jwt_claim_uid = 222 ) {
add_header X-jwt-claim-uid "$jwt_claim_uid" always;
add_header X-jwt-status "Redirect to $jwt_claim_url" always;
return 301 $jwt_claim_url;
}
if ( $jwt_claim_uid != 222 ) {
add_header X-jwt-claim-uid "$jwt_claim_uid" always;
add_header X-jwt-status "Invalid user, no redirect" always;
}
}
}As diretivas no bloco location informam ao NGINX Plus como processar solicitações HTTP que incluem um JWT. (Para obter informações sobre a configuração de registro definida pela diretiva access_log, consulte a próxima seção.) O NGINX Plus executa estas etapas:
- Extrai o JWT do argumento myjwt na string de solicitação (conforme especificado pelo argumento
tokenda diretivaauth_jwt). - Decodifica o JWT usando a chave de assinatura especificada pela diretiva
auth_jwt_key-file(neste caso, api_secret.jwk). Ele processa o payload da seguinte forma (essas ações são inerentes ao processamento de JWT e não têm diretivas correspondentes no NGINX Plus):- Verifica se o JWT não expirou, ou seja, se a data de expiração especificada pela declaração
expno payload não está no passado. - Cria um par de chave-valor para cada declaração no payload. O nome da chave é uma variável no formato
$jwt_claim_claim-name(por exemplo,$jwt_claim_uidpara a declaraçãouid).
- Verifica se o JWT não expirou, ou seja, se a data de expiração especificada pela declaração
- Registra todos os erros em /var/log/nginx/host.jwt.error.log no nível
debug. - Testa se o valor de
$jwt_claim_uidé222(conforme especificado pelas duas diretivasif) e envia a resposta apropriada ao cliente. É assim que as informações no JWT são usadas para realizar o roteamento baseado em conteúdo.Observação: O uso da diretivaifpara avaliar variáveis geralmente não é considerado uma prática recomendada, e normalmente recomendamos usar a diretivamapem vez disso. No entanto, para os fins deste exemplo simples, a diretivaiffunciona conforme o esperado.- Se o valor for
222, o NGINX Plus enviará uma resposta que redirecionará o cliente (por meio da diretivareturn) para a URL especificada na declaraçãourldo JWT. Para fins de depuração, ele adicionará dois cabeçalhos à resposta (por meio das diretivasadd_header): o primeiro capturará o valor da declaraçãouide o segundo registrará que o cliente foi redirecionado. - Se o valor não for
222, o NGINX Plus disponibilizará a página de índice padrão (conforme definido pelas diretivasrooteindexno mesmo blocolocation). Novamente, para fins de depuração, ele adicionará cabeçalhos que capturam o valor da declaraçãouide registram que o cliente não obteve acesso à URL especificada no JWT.
- Se o valor for
Na prática, a configuração permite que apenas usuários autorizados acessem recursos protegidos. Ou seja, os usuários com um JWT válido têm acesso à URL especificada no JWT, enquanto os usuários sem um JWT válido têm acesso a uma página padrão.
Registro de dados JWT
Concluímos a configuração do processamento de JWT para roteamento baseado em conteúdo definindo um formato de log chamado jwt, que é referenciado pela diretiva access_log em jwt-test.conf. Ele registra os dados do JWT no log de acesso.
- Adicione a seguinte diretiva
log_formatao arquivo /etc/nginx/nginx.conf:
log_format jwt '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'$jwt_header_alg $jwt_claim_uid $jwt_claim_url';- Esse formato inclui as duas declarações JWT usadas neste passo a passo (
uideurl), mas você pode registrar os dados de qualquer declaração JWT usando o nome da variável correspondente à declaração, no formato$jwt_claim_claim‑name. - Salve o arquivo nginx.conf e execute o comando a seguir para verificar a validade sintática da configuração completa (incluindo o novo arquivo jwt-test.conf). Corrija todos os erros relatados.
# nginx -t- Recarregue o NGINX Plus.
# nginx -s reloadTestando a configuração
Usando um navegador ou uma ferramenta de linha de comando como o curl, podemos testar se o NGINX Plus está validando corretamente o JWT, autenticando o cliente que o apresenta e realizando o roteamento baseado em conteúdo. (Para testar apenas a autenticação e a validação, sem o roteamento baseado em conteúdo, comente os dois blocos if em jwt-test.conf.)
Para executar o teste, incluímos o argumento myjwt na URL da solicitação, fornecendo o texto completo do JWT no qual a declaração url é 222. Novamente, adicionamos quebras de linha para facilitar a exibição.
http://example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiO
jE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW
1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9
lIiwidWlkIjoiMjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5le
GFtcGxlLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4
Este é o comando curl correspondente (sem quebras de linha, para que você possa copiá-lo e colá-lo, se quiser):
# curl -v example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4Como o valor da declaração uid no JWT é 222, esperamos que o NGINX Plus exiba o conteúdo da página restrita, http://secure.example.com.
Agora, fazemos um teste para verificar que, quando a declaração url no JWT não é 222, o NGINX Plus não exibe o conteúdo da página restrita, mas apresenta a página index.html do servidor local, neste caso, http://example.com/index.html.
Começamos gerando outro JWT em jwt.io com uma declaração uid diferente de 222; para fins de exemplo, usamos o valor 111. Esta é a URL da solicitação com esse JWT:
http://example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiO
jE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW
1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9
lIiwidWlkIjoiMTExIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5l
eGFtcGxlLmNvbSJ9.Ch9xqsGzB8fRVX-3CBuCxP1Ia3oGKB1OnO6qwi_oBgg
O comando curl é:
# curl -v example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMTExIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.Ch9xqsGzB8fRVX-3CBuCxP1Ia3oGKB1OnO6qwi_oBggNesse caso, esperamos que o NGINX Plus disponibilize http://example.com/index.html.
Em ambas as condições de teste, você pode usar uma ferramenta de inspeção de cabeçalhos (como curl ou as ferramentas de desenvolvedor fornecidas por alguns navegadores) para verificar se os novos cabeçalhos, X-jwt-claim-uid e X-jwt-status, foram adicionados à resposta.
Se você tiver algum problema durante os testes, verifique os logs de acesso e de erros em /var/log/nginx/host.jwt*. O log de erros, em particular, revela problemas com a verificação, o acesso ao arquivo de verificação e assim por diante.
Enviando o JWT em um cookie
Em nosso exemplo básico, o NGINX Plus extrai o JWT do argumento myjwt na URL da solicitação. O NGINX Plus também permite passar o JWT em um cookie (para obter detalhes, consulte a documentação de referência do NGINX JWT). No arquivo jwt-test.conf, altere a diretiva auth_jwt para que o primeiro elemento do parâmetro token seja $cookie em vez de $arg:
auth_jwt "JWT Test Realm" token=$cookie_myjwt;Para fornecer o JWT em um cookie chamado myjwt, o comando curl apropriado é:
# curl -v --cookie myjwt=JWT-text example.com/index.htmlExperimente você mesmo o roteamento baseado em conteúdo com JWTs: comece hoje mesmo sua avaliação gratuita de 30 dias do NGINX ou entre em contato conosco para conversar sobre seus casos de uso.
Sobre o autor

Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
Descubra como o F5 NGINX One aprimora o gerenciamento e a observabilidade de ambientes híbridos e multicloud ao oferecer um console web centralizado baseado em SaaS, com insights em tempo real, conformidade automatizada e gerenciamento simplificado de configurações.

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa
Descubra como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, operando como um API Gateway com a segurança de um Web Application Firewall e um Portal do Desenvolvedor, usando uma abordagem declarativa de API.

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor
Picos de tráfego e sobrecarga de servidores são preocupações sérias para varejistas online em qualquer época, mas especialmente durante a “Cyber Season” de compras de fim de ano. Detalhamos como você pode aproveitar as soluções de entrega de aplicações de nível de produção da NGINX para se preparar para aumentos repentinos de tráfego.

Distribuição segura de chaves privadas SSL com o NGINX
Descrevemos três maneiras progressivamente mais seguras de proteger chaves privadas SSL ao configurar o NGINX para processar tráfego HTTPS: permitir acesso de leitura apenas ao usuário root, criptografar as chaves com senhas armazenadas separadamente e distribuir as senhas a partir de um repositório central.
Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
O módulo JavaScript do NGINX lançado com o NGINX Plus R15 oferece suporte a subsolicitações, possibilitando uma classe totalmente nova de casos de uso para o NGINX Plus. Este exemplo completo também usa a API do NGINX Plus e os módulos de chave-valor para converter solicitações de API dos clientes em solicitações separadas para as APIs dos microsserviços que compõem um aplicativo.
Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus
Confira dicas para evitar o esgotamento de portas efêmeras com ajustes no kernel do Linux, conexões keepalive e conexões vinculadas dinamicamente a endereços IP locais.