jwt-verification: Biblioteca de verificação de JWT para nginx-module-lua com integração JWKS
Instalação
Se você ainda não configurou a assinatura do repositório RPM, inscreva-se. Depois, você pode prosseguir com os seguintes passos.
CentOS/RHEL 7 ou Amazon Linux 2
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 lua-resty-jwt-verification
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-jwt-verification
Para usar esta biblioteca Lua com NGINX, certifique-se de que o nginx-module-lua esteja instalado.
Este documento descreve lua-resty-jwt-verification v0.7.0 lançado em 30 de outubro de 2025.
Biblioteca de verificação de JWT para OpenResty.
Descrição
Biblioteca de verificação de JWT para OpenResty.
O objetivo do projeto é ser um substituto moderno e mais leve para lua-resty-jwt com suporte embutido para JWKS.
Este projeto não fornece recursos de manipulação ou criação de JWT: você pode apenas verificar/descriptografar tokens.
Objetivos não da biblioteca
- Criação/modificação de JWT
- Completo em recursos apenas para a completude dos RFCs.
- Recursos de RFCs sem sentido e inseguros (por exemplo, alg none) não serão implementados.
Diferenças em relação ao lua-resty-jwt
As principais diferenças são: - Nenhuma manipulação de JWT de qualquer tipo (você pode apenas descriptografá-los/verificá-los) - Estrutura interna mais simples, dependente de versões mais recentes do lua-resty-openssl e OpenSSL. - Suporta diferentes algoritmos JWE (veja as tabelas acima). - Verificação automática de JWT dada uma URL de endpoint HTTP JWKS.
Se algum dos pontos acima for um problema, ou se você precisar de compatibilidade com versões mais antigas do OpenResty, recomendo continuar com lua-resty-jwt.
Tipos
Tipos e verificações nulas são fornecidos com uso extensivo de EmmyLua annotations.
Integrações de plugins de IDE para EmmyLua: - Idea - VSCode
O arquivo ngx.d.lua na raiz do projeto fornece alguns stubs de ngx.
Recursos suportados
- Verificação de JWS: com chaves simétricas ou assimétricas.
- Descriptografia de JWE: com chaves simétricas ou assimétricas.
- Formato de chaves assimétricas suportadas:
- PEM
- DER
- JWK
- Validação de claims de JWT.
- Busca automática de JWKS e validação de JWT.
- estratégias de cache opcionais.
- JWTs aninhados (JWS em JWE)
Verificação de JWS
| Claims | Implementado |
|---|---|
| alg | |
| jku | |
| jwk | |
| kid | |
| x5u | |
| x5c | |
| x5t | |
| x5t#S256 | |
| typ | |
| cty | |
| crit |
| alg | Implementado | Requisitos de Implementação JOSE | Requisitos |
|---|---|---|---|
| HS256 | Requerido | ||
| HS384 | Opcional | ||
| HS512 | Opcional | ||
| RS256 | Recomendado | ||
| RS384 | Opcional | ||
| RS512 | Opcional | ||
| ES256 | Recomendado+ | ||
| ES384 | Opcional | ||
| ES512 | Opcional | ||
| PS256 | Opcional | ||
| PS384 | Opcional | ||
| PS512 | Opcional | ||
| none | Opcional | ||
| EdDSA | Obsoleto | ||
| ES256K | Opcional | ||
| Ed25519 | Opcional | *OpenSSL 3.0+ | |
| Ed448 | Opcional |
Descriptografia de JWE
| Claims | Implementado |
|---|---|
| alg | |
| enc | |
| zip | |
| jku | |
| jwk | |
| kid | |
| x5u | |
| x5c | |
| x5t | |
| x5t#S256 | |
| typ | |
| cty | |
| crit |
| kty | Implementado | Requisitos de Implementação JOSE |
|---|---|---|
| EC | Recomendado+ | |
| RSA | Requerido | |
| oct | Requerido | |
| OKP | Opcional |
| alg | Implementado | Requisitos de Implementação JOSE | Requisitos |
|---|---|---|---|
| RSA1_5 | Recomendado- | ||
| RSA-OAEP | Recomendado+ | ||
| RSA-OAEP-256 | Opcional | ||
| RSA-OAEP-384 | Opcional | ||
| RSA-OAEP-512 | Opcional | ||
| A128KW | Recomendado | *OpenSSL 3.0+ | |
| A192KW | Opcional | *OpenSSL 3.0+ | |
| A256KW | Recomendado | *OpenSSL 3.0+ | |
| dir | Recomendado | ||
| ECDH-ES | Recomendado+ | ||
| ECDH-ES+A128KW | Recomendado | *OpenSSL 3.0+ | |
| ECDH-ES+A192KW | Opcional | *OpenSSL 3.0+ | |
| ECDH-ES+A256KW | Recomendado | *OpenSSL 3.0+ | |
| A128GCMKW | Opcional | ||
| A192GCMKW | Opcional | ||
| A256GCMKW | Opcional | ||
| PBES2-HS256+A128KW | Opcional | ||
| PBES2-HS384+A192KW | Opcional | ||
| PBES2-HS512+A256KW | Opcional |
*O primeiro lançamento oficial do OpenResty incluindo OpenSSL 3.0+ é OpenResty 1.27.1.1 que foi lançado com OpenSSL 3.0.15 (Sim, a horrível e lenta série OpenSSL 3.0...).
Portanto, por favor, use OpenResty 1.27.1.2 como mínimo, que foi lançado com OpenSSL 3.4.1.
| enc | Implementado | Requisitos de Implementação JOSE |
|---|---|---|
| A128CBC-HS256 | Requerido | |
| A192CBC-HS384 | Opcional | |
| A256CBC-HS512 | Requerido | |
| A128GCM | Recomendado | |
| A192GCM | Opcional | |
| A256GCM | Recomendado |
Estratégias de cache para recuperação de JWKS
| Estratégia de Cache | Implementado |
|---|---|
| sem cache | |
| local (shared_dict) |
Uso da verificação de JWT
jwt.decode_header_unsafe
sintaxe: header, err = jwt.decode_header_unsafe(token)
Lê um cabeçalho jwt e o converte em uma tabela lua.
Importante: este método não valida a assinatura do JWT! Use apenas se você precisar inspecionar o cabeçalho do token sem realizar a validação completa.
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MTY2NDkwNzJ9._MwFdsBPSyci9iARpoAaulReGcn1q7mKiPZjR2JDvdY"
local header, err = jwt.decode_header_unsafe(token)
if not header then
return nil, "jwt malformado: " .. err
end
print("alg: " .. header.alg) -- alg: HS256
jwt.verify
sintaxe: decoded_token, err = jwt.verify(token, secret, options?)
Valida um token JWS e o converte em uma tabela lua.
O parâmetro opcional options pode ser passado para configurar o validador de token. Os campos válidos são:
- valid_signing_algorithms (dictalg permitidos usados para validar o JWT.
- typ (string | nil): se não nulo, garante que o claim JWT typ corresponda ao valor passado.
- issuer (string | nil): se não nulo, garante que o claim JWT iss corresponda ao valor passado.
- audiences (string | tabela | nil): se não nulo, garante que o claim JWT aud corresponda a um dos valores fornecidos.
- subject (string | nil): se não nulo, garante que o claim JWT sub corresponda ao valor passado.
- jwtid (string | nil): se não nulo, garante que o claim JWT jti corresponda ao valor passado.
- ignore_not_before (bool): Se verdadeiro, o claim JWT nbf será ignorado.
- ignore_expiration (bool): Se verdadeiro, o claim JWT exp será ignorado.
- current_unix_timestamp (datetime | nil): os claims JWT nbf e exp serão validados em relação a este timestamp. Se nulo, usará a data e hora atuais fornecidas por ngx.time().
- timestamp_skew_seconds (int): Quantos segundos de margem a biblioteca pode usar para verificar a expiração do token em relação ao tempo atual. Útil quando os relógios não estão sempre exatamente sincronizados. Definir este valor muito alto pode representar problemas de segurança.
Valores padrão para os campos options:
local verify_default_options = {
valid_signing_algorithms = {
["HS256"]="HS256", ["HS384"]="HS384", ["HS512"]="HS512",
["RS256"]="RS256", ["RS384"]="RS384", ["RS512"]="RS512",
["ES256"]="ES256", ["ES384"]="ES384", ["ES512"]="ES512",
["PS256"]="PS256", ["PS384"]="PS384", ["PS512"]="PS512",
["ES256K"]="ES256K", ["Ed25519"]="Ed25519", ["Ed448"]="Ed448",
},
typ = nil,
issuer = nil,
audiences = nil,
subject = nil,
jwtid = nil,
ignore_not_before = false,
ignore_expiration = false,
current_unix_timestamp = nil,
timestamp_skew_seconds = 1,
}
Exemplo mínimo com chaves simétricas:
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MTY2NTUwMTV9.NuEhIzUuufJgPZ8CmCPnD4Vrw7EnTyWD8bGtYCwuDZ0"
local decoded_token, err = jwt.verify(token, "superSecretKey")
if not decoded_token then
return nil, "jwt inválido: " .. err
end
print(decoded_token.header.alg) -- HS256
print(decoded_token.payload.foo) -- bar
Exemplo mínimo com chaves assimétricas:
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MTY2Njg2Mzd9.H6PE-zLizMMqefx8DG4X5glVjyxR9UNT225Tq2yufHhu4k9K0IGttpykjMCG8Ck_4Qt2ezEWIgoiWhSn1rv_zwxe7Pv-B09fDs7h1hbASi5MZ0YVAmK9ID1RCKM_NTBEnPLot_iopKZRj2_J5F7lvXwJDZSzEAFJZdrgjKeBS4saDZAv7SIL9Nk75rdhgY-RgRwsjmTYSksj7eioRJJLHifrMnlQDbdrBD5_Qk5tD6VPcssO-vIVBUAYrYYTa7M7A_v47UH84zDtzNYBbk9NrDbyq5-tYs0lZwNhIX8t-0VAxjuCyrrGZvv8_O01pdi90kQmntFIbaiDiD-1WlGcGA"
local decoded_token, err = jwt.verify(token, "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvXFhNyhFWuWtFSJqfOAw\np42lLIn9kB9oaciiKgNAYZ8SYw5t9Fo+Zh7IciVijn+cVS2/aoBNg2HhfdYgfpQ/\nsb6jwbRqFMln2GmG+X2aJ2wXMJ/QfxrPFdO9L36bAEwkubUTYXwgMSm1KqWRN8xX\n+oBu+dbyzw7iUbrmw0ybzXKZLJvetCvmt0reU5TvdwoczOWFBSKeYnzBrC6hISD8\n8TYDJ4tiw1EWVOupQGqgel0KjC7iwdIYi7PROn6/1MMnF48zlBbT/7/zORj84Z/y\nDnmxZu1MQ07kHqXDRYumSfCerg5Xw5vde7Tz8O0TWtaYV3HJXNa0VpN5OI3L4y7P\nhwIDAQAB\n-----END PUBLIC KEY-----")
if not decoded_token then
return nil, "jwt inválido: " .. err
end
print(decoded_token.header.alg) -- RS256
print(decoded_token.payload.foo) -- bar
Exemplos com options personalizadas:
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MTY2NTUwMTV9.NuEhIzUuufJgPZ8CmCPnD4Vrw7EnTyWD8bGtYCwuDZ0"
local decoded_token, err = jwt.verify(token, "superSecretKey", {
valid_signing_algorithms = {["HS256"]="HS256", ["HS384"]="HS384", ["HS512"]="HS512"}, -- permite apenas algoritmos da família HS
audiences = {"user", "admin"}, -- `aud` deve ser um dos seguintes
ignore_not_before = true -- ignora o claim `nbf` (não recomendado)
})
if not decoded_token then
return nil, "jwt inválido: " .. err
end
print(decoded_token.header.alg) -- HS256
print(decoded_token.payload.foo) -- bar
jwt.decrypt
sintaxe: decoded_token, err = jwt.decrypt(token, secret, options?)
Descriptografa e valida um token JWE e o converte em uma tabela lua.
O parâmetro opcional options pode ser passado para configurar o validador de token. Os campos válidos são:
- valid_encryption_alg_algorithms (dictalg permitidos usados para descriptografar o JWT.
- valid_encryption_enc_algorithms (dictenc permitidos usados para descriptografar o JWT.
- typ (string | nil): se não nulo, garante que o claim JWT typ corresponda ao valor passado.
- issuer (string | nil): se não nulo, garante que o claim JWT iss corresponda ao valor passado.
- audiences (string | tabela | nil): se não nulo, garante que o claim JWT aud corresponda a um dos valores fornecidos.
- subject (string | nil): se não nulo, garante que o claim JWT sub corresponda ao valor passado.
- jwtid (string | nil): se não nulo, garante que o claim JWT jti corresponda ao valor passado.
- ignore_not_before (bool): Se verdadeiro, o claim JWT nbf será ignorado.
- ignore_expiration (bool): Se verdadeiro, o claim JWT exp será ignorado.
- current_unix_timestamp (datetime | nil): os claims JWT nbf e exp serão validados em relação a este timestamp. Se nulo, usará a data e hora atuais fornecidas por ngx.time().
- timestamp_skew_seconds (int): Quantos segundos de margem a biblioteca pode usar para verificar a expiração do token em relação ao tempo atual. Útil quando os relógios não estão sempre exatamente sincronizados. Definir este valor muito alto pode representar problemas de segurança.
- allow_nested_jwt (bool): Permite a verificação de JWTs que contêm outro JWT (ou seja, JWTs aninhados ou jwt-in-jwt). Isso é opcional, pois os claims a serem validados estão sempre dentro do JWT mais interno e NÃO serão validados automaticamente. Cabe a você validar recursivamente os JWTs internos retornados como uma string no campo payload por esta biblioteca. Um JWT aninhado DEVE conter a chave de cabeçalho cty configurada como JWT para ser reconhecido como tal.
Valores padrão para os campos options:
local decrypt_default_options = {
valid_encryption_alg_algorithms = {
["RSA-OAEP"]="RSA-OAEP",
["RSA-OAEP-256"]="RSA-OAEP-256", ["RSA-OAEP-384"]="RSA-OAEP-384", ["RSA-OAEP-512"]="RSA-OAEP-512",
["A128KW"]="A128KW", ["A192KW"]="A192KW", ["A256KW"]="A256KW",
["dir"]="dir",
["ECDH-ES"]="ECDH-ES",
["ECDH-ES+A128KW"]="ECDH-ES+A128KW",
["ECDH-ES+A192KW"]="ECDH-ES+A192KW",
["ECDH-ES+A256KW"]="ECDH-ES+A256KW",
},
valid_encryption_enc_algorithms = {
["A128CBC-HS256"]="A128CBC-HS256",
["A192CBC-HS384"]="A192CBC-HS384",
["A256CBC-HS512"]="A256CBC-HS512",
["A128GCM"]="A128GCM",
["A192GCM"]="A192GCM",
["A256GCM"]="A256GCM",
},
typ = nil,
issuer = nil,
audiences = nil,
subject = nil,
jwtid = nil,
ignore_not_before = false,
ignore_expiration = false,
current_unix_timestamp = nil,
timestamp_skew_seconds = 1,
allow_nested_jwt = false,
}
Exemplo mínimo com chaves simétricas:
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.zAIq7qVAEO-eCG6gOdd3ld8_IHzeq3UlaWLHF2IDn6nNUuHh5n_i4w.5CM864cgiBgFPwluW4ViRg.mUeX7zHDVNsXhys0XO5S4w.t3yAR_HU0GDTEyCbpRa6BQ"
local decoded_token, err = jwt.decrypt(token, "superSecretKey12")
if not decoded_token then
return nil, "jwt inválido: " .. err
end
print(decoded_token.header.alg) -- A128KW
print(decoded_token.header.enc) -- A128CBC-HS256
print(decoded_token.payload.foo) -- bar
Exemplo mínimo com chaves assimétricas em formato PEM:
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkEyNTZHQ00iLCJlcGsiOnsieCI6IkFJdkVhSzVKZGl6d1I5ZFMzRUN2Y0dKMGNHWXNFejdpYWJwRUp1bE0tWDAiLCJjcnYiOiJYMjU1MTkiLCJrdHkiOiJPS1AifX0.QFfmPVYjk1PoyhE7elaDgUdUGGeAECLo7jB4ghq_8MIRXV3VKO1yAA.XITF2apHB5roeUsx.08T0gALwkb6Wibr2Og.IJoh3U_tspnMx_mWelRT5g"
local decoded_token, err = jwt.decrypt(token, "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VuBCIEIMCxXl/FEuh3pGo1Z++QRs2vudqkGd63mK0Js0f6y+55\n-----END PRIVATE KEY-----", nil)
if not decoded_token then
return nil, "jwt inválido: " .. err
end
print(decoded_token.header.alg) -- ECDH-ES+A128KW
print(decoded_token.header.enc) -- A256GCM
print(decoded_token.payload.foo) -- bar
Exemplos com options personalizadas:
local jwt = require("resty.jwt-verification")
local token = "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.zAIq7qVAEO-eCG6gOdd3ld8_IHzeq3UlaWLHF2IDn6nNUuHh5n_i4w.5CM864cgiBgFPwluW4ViRg.mUeX7zHDVNsXhys0XO5S4w.t3yAR_HU0GDTEyCbpRa6BQ"
local decoded_token, err = jwt.decrypt(token, "superSecretKey12", {
valid_encryption_alg_algorithms = {["A128KW"]="A128KW"}, -- permite apenas algoritmos da família A128KW (requer OpenSSL 3.0+)
valid_encryption_enc_algorithms = {["A128CBC-HS256"]="A128CBC-HS256"}, -- permite apenas codificações da família A128CBC
audiences = {"user", "admin"}, -- `aud` deve ser um dos seguintes
ignore_not_before = true -- ignora o claim `nbf` (não recomendado)
})
if not decoded_token then
return nil, "jwt inválido: " .. err
end
print(decoded_token.header.alg) -- A128KW
print(decoded_token.header.enc) -- A128CBC-HS256
print(decoded_token.payload.foo) -- bar
Uso da verificação de JWKS
O módulo resty.jwt-verification-jwks implementa a recuperação automática de JWKS de um endpoint HTTP e a subsequente validação de JWT com as chaves obtidas.
Os módulos resty.jwt-verification-jwks-cache-* implementam estratégias de cache JWKS opcionais. Apenas uma estratégia de cache pode ser habilitada por vez; se nenhuma estiver habilitada, o endpoint JWKS será chamado uma vez para cada JWT a ser validado.
jwks.init
sintaxe: ok, err = jwks.init(cache_strategy?)
Inicializa o módulo jwks e opcionalmente especifica uma estratégia de cache.
Esta função deve ser chamada apenas uma vez e preferencialmente na seção init_by_lua_file.
local jwks = require("resty.jwt-verification-jwks")
-- inicializa sem cache
local ok, err = jwks.init(nil)
if not ok then
ngx.say("Erro ao inicializar o módulo jwks: ", err)
end
-- ou ...
-- inicializa com cache local baseado no dicionário de memória compartilhada do OpenResty.
-- adicione isso na seção `http` da sua configuração do nginx: `lua_shared_dict resty_jwt_verification_cache_jwks 10m;`
-- veja https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/#ngxshareddict
local jwks_cache_local = require("resty.jwt-verification-jwks-cache-local")
local ok, err = jwks.init(jwks_cache_local)
if not ok then
ngx.say("Erro ao inicializar o módulo jwks: ", err)
end
Você pode implementar seu próprio cache e passá-lo no método de inicialização. Aqui está um exemplo de como:
local my_cache = {}
---Obtém a string de entrada em cache para a chave.
---@param key string Chave do cache.
---@return string|nil value Retorna o resultado em cache como string se presente, nil caso contrário.
function my_cache.get(key)
-- TODO
end
---Cache de dados sob a chave até a expiração.
---@param key string Chave do cache.
---@param value string Valor do cache.
---@param expiry integer Expiração da entrada do cache em segundos.
---@return boolean|nil ok verdadeiro em caso de sucesso
---@return string|nil err nil em caso de sucesso, mensagem de erro caso contrário.
function my_cache.setex(key, value, expiry)
-- TODO
end
local ok, err = jwks.init(my_cache)
if not ok then
ngx.say("Erro ao inicializar o módulo jwks: ", err)
end
jwks.set_http_timeouts_ms
sintaxe: jwks.set_http_timeouts_ms(connect, send, read)
Define os timeouts do cliente HTTP em milissegundos usados para buscar JWKS.
local jwks = require("resty.jwt-verification-jwks")
jwks.set_http_timeouts_ms(5000, 5000, 5000)
jwks.set_http_ssl_verify
sintaxe: jwks.set_http_ssl_verify(enabled)
Habilita/desabilita a verificação TLS usada pelo cliente HTTP para buscar JWKS.
Por padrão, todos os certificados TLS são verificados. Se o endpoint JWKS estiver usando certificados autoassinados, adicione o respectivo CA raiz ao armazenamento de certificados do OS ou desative a verificação de certificados com este endpoint (isso é inseguro).
local jwks = require("resty.jwt-verification-jwks")
jwks.set_http_ssl_verify(false)
jwks.set_cache_ttl
sintaxe: jwks.set_http_ssl_verify(enabled)
Altera o TTL de cache padrão. O valor padrão é 12 horas.
Nota: O TTL de cache só pode ser usado quando o módulo jwks foi inicializado com um cache. Veja como habilitar o cache.
local jwks = require("resty.jwt-verification-jwks")
jwks.set_cache_ttl(2 * 3600) -- 2h
jwks.fetch_jwks
sintaxe: payload, err = jwks.fetch_jwks(endpoint)
Busca manualmente JWKS do endpoint HTTP; o payload retornado, em caso de sucesso, é o corpo da resposta HTTP como string: Nenhuma verificação é realizada para saber se o payload contém JWKS ou algo mais.
Se uma estratégia de cache foi habilitada, o endpoint tentará buscá-lo primeiro no cache. Após uma falta de cache e a recuperação bem-sucedida de JWKS via HTTP, o cache será atualizado com o resultado.
local jwks = require("resty.jwt-verification-jwks")
payload, err = jwks.fetch_jwks("https://www.googleapis.com/oauth2/v3/certs")
if payload == nil then
print("falha ao buscar JWKS: ", err)
return
end
print(payload) -- '{"keys":[{"alg":"RS256","e":"AQAB","kid":"882503a5fd56e9f734dfba5c50d7bf48db284ae9","kty":"RSA","n":"woRUr445_ODXrFeynz5L208aJkABOKQHEzbfGM_V1ijkYZWZKY0PXKPP_wRKcE4C6OyjDNd5gHh3dF5QsVhVDZCfR9QjTf94o4asngrHzdOcfQ0pZIvzu_vzaVG82VGLM-2rKQp8uz06A6TbUzbIv9wQ8wQpYDIdujNkLqL22Mkb2drPxm9Y9I05PmVdkkvAbu4Q_KRJWxykOigHp-hVBmpYS2P3xuX56gM7ZRcXXJKKUfrGel4nDhSIAAD1wBNcVVgKbb0TYfZmVpRSCji_b6JHjqYhYjUasdotYJzWl7quAFsN_X_4j-cHZ30OS81j--OiIxWpL11y1kcbE0u-Dw","use":"sig"},{"n":"m7GlcF1ExRB4braT7sDnZvlY3wpqX9krkVRqcVA-m43FWFYBtuSpd-lc0EV8R8TO180y0tSgJc7hviI1IBJQlNa7XkjVGhY0ZFUp5rTpC45QbA9Smo4CLa5HQIf-69rkkovjFNMuDQvNiYCgRPLyRjmQbN2uHl4fU3hhf5qFqKTKo7eLCZiEMjrOkTXziA7xJJigUGe-ab8U-AXNH1fnCbejzHEIxL0eUG_4r4xddImOxETDO5T65AQCeqs7vtYos2xq5SLFuaUsithRQ-IMm3OlcVhMjBYt6uvGS6IdMjKon4wThCxEqAEXg0nahiGjnQCW176SNF152__TOjQVwQ","alg":"RS256","kty":"RSA","use":"sig","kid":"8e8fc8e556f7a76d08d35829d6f90ae2e12cfd0d","e":"AQAB"}]}'
jwks.verify_jwt_with_jwks
sintaxe: jwt, err = jwks.verify_jwt_with_jwks(jwt_token, jwks_endpoint, jws_options?)
Dado um jwt_token assinado como string, verifica sua assinatura com JWKS fornecido pelo serviço HTTP encontrado em jwks_endpoint.
Em caso de sucesso, o JWT verificado é retornado como uma tabela lua, caso contrário, nil e um erro são retornados.
O parâmetro opcional jws_options pode ser passado para configurar o validador de token ao chamar jwt.verify após ter buscado com sucesso o JWKS. Veja a documentação respectiva de jwt.verify para mais informações sobre quais opções podem ser passadas.
local jwks = require("resty.jwt-verification-jwks")
jwt, err = jwks.verify_jwt_with_jwks("<MEU_JWT>", "http://meuservico:8888/.well-known/jwks.json", nil)
if jwt == nil then
print("falha ao verificar jwt: ", err)
return
end
print(jwt.header.alg)
print(tostring(jwt.payload))
jwks.decrypt_jwt_with_jwks
sintaxe: jwt, err = jwks.decrypt_jwt_with_jwks(jwt_token, jwks_endpoint, jwe_options?)
Dado um jwt_token criptografado como string, descriptografa-o com JWKS fornecido pelo serviço HTTP encontrado em jwks_endpoint.
Em caso de sucesso, o JWT descriptografado é retornado como uma tabela lua, caso contrário, nil e um erro são retornados.
O parâmetro opcional jwe_options pode ser passado para configurar o validador de token ao chamar jwt.decrypt após ter buscado com sucesso o JWKS. Veja a documentação respectiva de jwt.decrypt para mais informações sobre quais opções podem ser passadas.
local jwks = require("resty.jwt-verification-jwks")
jwt, err = jwks.decrypt_jwt_with_jwks("<MEU_JWT>", "http://meuservico:8888/.well-known/jwks.json", nil)
if jwt == nil then
print("falha ao descriptografar jwt: ", err)
return
end
print(jwt.header.alg)
print(jwt.header.enc)
print(tostring(jwt.payload))
RFCs usadas como referência
- RFC 7515 JSON Web Signature (JWS)
- RFC 7516 JSON Web Encryption (JWE)
- RFC 7517 JSON Web Key (JWK)
- RFC 7518 JSON Web Algorithms (JWA)
- RFC 7519 JSON Web Token (JWT)
- RFC 7520 Exemplos de Proteção de Conteúdo Usando Assinatura e Criptografia de Objetos JSON (JOSE)
- IANA JOSE assignments
Executar testes
Configuração
Instale o conjunto de testes:
sudo cpan Test::Nginx
Instale o openresty: veja https://openresty.org/en/linux-packages.html
Executar
export PATH=/usr/local/openresty/nginx/sbin:$PATH
prove -r t
Executar benchmarks
O conjunto de testes Test::Nginx tem integração de benchmarking embutida com weighttp.
Aumentar limites do sysctl
Se você planeja estressar a biblioteca, pode ser necessário aumentar os limites do sistema.
cat > /etc/sysctl.d/openresty-benchmarks.conf << EOF
net.ipv4.ip_local_port_range=2048 65535
net.ipv4.tcp_tw_reuse=1
net.core.netdev_max_backlog=2000
net.ipv4.tcp_max_syn_backlog=2048
EOF
## aplicar mudanças
sudo sysctl -p /etc/sysctl.d/openresty-benchmarks.conf
Lançar testes
Eu criei alguns cenários pseudo-reais dentro da pasta benchmarks.
## para mais informações sobre a sintaxe: https://openresty.gitbooks.io/programming-openresty/content/testing/test-modes.html
export TEST_NGINX_BENCHMARK='50000 10'
prove -r ./benchmarks
Por padrão, apenas 1 trabalhador do nginx e 1 núcleo de CPU serão usados para realizar os benchmarks. Para aumentar os limites de trabalhadores, altere a diretiva workers(1); dentro dos arquivos .t e execute novamente o benchmark.
GitHub
Você pode encontrar dicas de configuração adicionais e documentação para este módulo no repositório GitHub para nginx-module-jwt-verification.