phantom-token: Módulo Phantom Token do NGINX
Instalação
Você pode instalar este módulo em qualquer distribuição baseada em RHEL, incluindo, mas não se limitando a:
- RedHat Enterprise Linux 7, 8, 9 e 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 e Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-phantom-token
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-phantom-token
Ative o módulo adicionando o seguinte no topo de /etc/nginx/nginx.conf:
load_module modules/ngx_curity_http_phantom_token_module.so;
Este documento descreve o nginx-module-phantom-token v2.0.0 lançado em 22 de maio de 2025.
Módulo NGINX que introspecta tokens de acesso de acordo com RFC 7662, produzindo um "token fantasma" que pode ser encaminhado para APIs e serviços Web de back-end. Leia mais sobre a abordagem do Token Fantasma.
Este módulo, quando ativado, filtra as requisições de entrada, negando acesso àquelas que não possuem um token de acesso OAuth válido apresentado em um cabeçalho Authorization. A partir deste cabeçalho, o access_token é extraído e introspectado usando o endpoint configurado. O Curity Identity Server responde a esta requisição de acordo com o padrão. Para um token de acesso ativo, o corpo da resposta do Curity Identity Server contém o JWT que substitui o token de acesso no cabeçalho da requisição que é encaminhada pelo NGINX para o back-end. Se o token não for válido ou estiver ausente, nenhuma requisição ao back-end é feita e o chamador recebe um erro 401, não autorizado. Este fluxo é mostrado no diagrama a seguir:

As chamadas iniciais pelo aplicativo (web ou nativo) são feitas usando OpenID Connect (OIDC). A parte importante é que o token que é emitido é um token de acesso opaco. É um GUID ou UUID ou alguns punhados de bytes aleatórios; não há dados relacionados à identidade neste token. É um fantasma dos dados reais do usuário, daí o nome -- token fantasma. O aplicativo apresenta o token ao gateway NGINX de acordo com a especificação de Uso de Token Bearer (ou seja, RFC 6750). Este padrão diz que o aplicativo deve enviar o token fantasma no cabeçalho de requisição Authorization.
Uma vez que o servidor NGINX recebe o token de acesso, este módulo será ativado. Usando uma configuração como a abaixo, este módulo interrogará a requisição, encontrará o token e fará uma chamada lateral ao Curity Identity Server. Esta requisição de serviço web será feita usando o padrão de Introspecção de Token (RFC 7662) com um tipo Accept de application/jwt (como definido em RFC 7519). Isso fará com que o Curity Identity Server retorne não JSON, mas apenas um JWT. Então, o módulo encaminhará o token JWT para as APIs e microsserviços de back-end.
Se o módulo também estiver configurado para armazenar em cache os resultados da chamada ao Curity Identity Server (o que deve ser feito para casos de produção), o token fantasma será usado como uma chave de cache para o token JWT correspondente. Isso eliminará a necessidade de chamadas subsequentes ao Curity Identity Server enquanto ele informar ao módulo NGINX que pode armazenar em cache o JWT.
O resumo é um gateway de API muito simples que é extremamente rápido, altamente escalável e sem nenhum recurso desnecessário que possa atrapalhar. Todo o código está aqui, então é fácil de mudar e usar com outros servidores OAuth também!
Diretrizes de Configuração do Módulo
A versão 2.0 introduziu uma MUDANÇA QUEBRADORA para usar diretrizes de configuração atualizadas.\ Veja instruções de configuração anteriores para configurar versões mais antigas.
Diretrizes de Configuração Obrigatórias
As diretrizes nesta subseção são obrigatórias; se alguma delas for omitida, o módulo será desativado.
phantom_token
Sintaxe:
phantom_tokenon|offPadrão:
offContexto:
location
phantom_token_introspection_endpoint
Sintaxe:
phantom_token_introspection_endpointstringPadrão:
—Contexto:
location
Diretrizes de Configuração Opcionais
As seguintes diretrizes são opcionais e não precisam ser configuradas.
phantom_token_realm
Sintaxe:
phantom_token_realmstringPadrão:
apiContexto:
location
O nome do reino protegido ou escopo de proteção que deve ser usado quando um cliente não fornece um token de acesso.
Exemplo de configuração:
location / {
...
phantom_token_realm "myGoodRealm";
}
phantom_token_scopes
Sintaxe:
phantom_token_scopesstringPadrão:
—Contexto:
location
A lista de escopos separados por espaço que o servidor deve informar ao cliente que são necessários quando ele não fornece um token de acesso.
Exemplo de configuração:
location / {
...
phantom_token_scopes "scope_a scope_b scope_c";
}
phantom_token_scope
Sintaxe:
phantom_token_scopestringPadrão:
—Contexto:
location
Um array de escopos que o servidor deve informar ao cliente que são necessários quando ele não fornece um token de acesso. Se phantom_token_scopes também estiver configurado, esse valor terá prioridade sobre estes.
Exemplo de configuração:
location / {
...
phantom_token_scope "scope_a";
phantom_token_scope "scope_b";
phantom_token_scope "scope_c";
}
Exemplo de Configuração
Carregando o Módulo
Se o módulo for baixado do GitHub ou compilado como uma biblioteca compartilhada (o padrão) e não for explicitamente compilado no NGINX, ele precisará ser carregado usando a diretiva load_module. Isso deve ser feito na parte main da configuração do NGINX:
load_module modules/ngx_curity_http_phantom_token_module.so;
O arquivo pode ser um caminho absoluto ou relativo. Se não for absoluto, deve ser relativo ao diretório raiz do NGINX.
Parâmetros do NGINX para o Endpoint de Introspecção
Você também deve configurar os seguintes parâmetros do NGINX para a subrequisição de introspecção:
location curity {
internal;
proxy_pass_request_headers off;
proxy_set_header Accept "application/jwt";
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";
proxy_pass "https://curity.example.com/oauth/v2/oauth-introspect";
}
| Configuração de Introspecção | Descrição |
|---|---|
| internal | Impede que o endpoint de introspecção esteja disponível externamente. |
| proxy_pass_request_headers | Defina como off para evitar usar os cabeçalhos da requisição principal na subrequisição de introspecção. |
| Cabeçalho Accept | Configure um valor fixo de application/jwt. |
| Cabeçalho Content-Type | Configure um valor fixo de application/x-www-form-urlencoded. |
| Cabeçalho Authorization | Configure uma credencial básica com o ID do cliente de introspecção e o segredo do cliente. |
Para obter a credencial básica, concatene o ID do cliente, um caractere de dois pontos e o segredo do cliente, e então codifique-os em base64. O seguinte comando fornece um exemplo.
echo -n "my_client_id:my_client_secret" | base64
Configuração Simples
A seguinte é uma configuração simples que pode ser usada em ambientes de demonstração ou desenvolvimento onde o proxy reverso do NGINX está no mesmo host que o Curity Identity Server:
server {
location /api {
phantom_token on;
phantom_token_introspection_endpoint curity;
proxy_pass https://example.com/api;
}
location curity {
internal;
proxy_pass_request_headers off;
proxy_set_header Accept "application/jwt";
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";
proxy_pass "https://curity.example.com/oauth/v2/oauth-introspect";
}
}
Configuração Complexa
A seguinte é uma configuração mais complexa onde o proxy reverso do NGINX está em um host separado do Curity Identity Server:
server {
server_name server1.example.com;
location /api {
phantom_token on;
phantom_token_introspection_endpoint curity;
phantom_token_realm "myGoodAPI";
phantom_token_scopes "scope_a scope_b scope_c";
proxy_pass https://example.com/api;
}
location curity {
internal;
proxy_pass_request_headers off;
proxy_set_header Accept "application/jwt";
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";
proxy_pass "https://server2.example.com:8443/oauth/v2/oauth-introspect";
}
}
server {
listen 8443;
server_name server2.example.com;
location / {
proxy_pass "https://curity.example.com";
}
}
Configuração Mais Avançada com Servidores Separados e Cache
Este módulo aproveita a diretiva proxy_cache embutida do NGINX. Para poder armazenar em cache as requisições feitas ao endpoint de introspecção, além de proxy_cache_path no contexto http e proxy_cache no contexto location, você deve adicionar as seguintes 3 diretrizes no contexto location do endpoint de introspecção.
proxy_cache_methods POST;Requisições POST não são armazenadas em cache por padrão.proxy_cache_key $request_body;A chave do cache está relacionada ao access_token enviado na requisição original. Requisições diferentes usando o mesmo access_token atingem o mesmo cache.proxy_ignore_headers Set-Cookie;O NGINX não armazenará em cache a resposta se o cabeçalhoSet-Cookienão for ignorado.
http {
proxy_cache_path /path/to/cache/cache levels=1:2 keys_zone=my_cache:10m max_size=10g
inactive=60m use_temp_path=off;
server {
server_name server1.example.com;
location /api {
phantom_token on;
phantom_token_introspection_endpoint curity;
phantom_token_scopes "scope_a scope_b scope_c";
phantom_token_realm "myGoodAPI";
proxy_pass https://example.com/api;
}
location curity {
internal;
proxy_pass_request_headers off;
proxy_set_header Accept "application/jwt";
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";
proxy_cache_methods POST;
proxy_cache my_cache;
proxy_cache_key $request_body;
proxy_ignore_headers Set-Cookie;
proxy_pass "https://server2.example.com:8443/oauth/v2/oauth-introspect";
}
}
server {
listen 8443;
server_name server2.example.com;
location / {
proxy_pass "https://curity.example.com";
}
}
}
Configuração Sem Cache
É recomendável armazenar em cache os resultados da chamada ao Curity Identity Server para evitar acionar uma requisição de introspecção para cada requisição de API. Se você deseja desativar o cache, deve aumentar o padrão de proxy_buffer_size para garantir que o módulo possa ler JWTs grandes. Faça isso atualizando a configuração da requisição de introspecção como no seguinte exemplo.
http {
server {
server_name server1.example.com;
location /api {
phantom_token on;
phantom_token_introspection_endpoint curity;
phantom_token_scopes "scope_a scope_b scope_c";
phantom_token_realm "myGoodAPI";
proxy_pass https://example.com/api;
}
location curity {
internal;
proxy_pass_request_headers off;
proxy_set_header Accept "application/jwt";
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";
proxy_ignore_headers Set-Cookie;
proxy_buffer_size 16k;
proxy_buffers 4 16k;
proxy_pass "https://server2.example.com:8443/oauth/v2/oauth-introspect";
}
}
server {
listen 8443;
server_name server2.example.com;
location / {
proxy_pass "https://curity.example.com";
}
}
}
Mais Informações
Para mais informações sobre o Curity Identity Server, suas capacidades e como usá-lo para emitir tokens fantasmas para microsserviços, visite curity.io. Para informações de fundo sobre como usar o Curity Identity Server para proteger o acesso à API, veja nossos recursos de segurança de API.
GitHub
Você pode encontrar dicas adicionais de configuração e documentação para este módulo no repositório do GitHub para nginx-module-phantom-token.