jwt-verification: Biblioteca de verificación de JWT para nginx-module-lua con integración de JWKS
Instalación
Si aún no has configurado la suscripción al repositorio RPM, regístrate. Luego, puedes proceder con los siguientes pasos.
CentOS/RHEL 7 o 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 con NGINX, asegúrate de que nginx-module-lua esté instalado.
Este documento describe lua-resty-jwt-verification v0.7.0 lanzado el 30 de octubre de 2025.
Biblioteca de verificación de JWT para OpenResty.
Descripción
Biblioteca de verificación de JWT para OpenResty.
El objetivo del proyecto es ser un reemplazo moderno y más ligero para lua-resty-jwt con soporte integrado para JWKS.
Este proyecto no proporciona características de manipulación o creación de JWT: solo puedes verificar/desencriptar tokens.
Objetivos no del proyecto
- Creación/modificación de JWT
- Completo en características por el bien de la completitud de los RFCs.
- Características RFCs sin sentido y no seguras (por ejemplo, alg none) no serán implementadas.
Diferencias con lua-resty-jwt
Las principales diferencias son: - No hay manipulación de JWT de ningún tipo (solo puedes desencriptarlos/verificarlos) - Estructura interna más simple que depende de versiones más recientes de lua-resty-openssl y OpenSSL. - Soporta diferentes algoritmos JWE (ver tablas arriba). - Verificación automática de JWT dado el endpoint HTTP de JWKS.
Si alguno de los puntos anteriores es un problema, o necesitas compatibilidad con versiones más antiguas de OpenResty, te recomiendo quedarte con lua-resty-jwt.
Tipos
Los tipos y las verificaciones de nulos se proporcionan con un uso extenso de EmmyLua annotations.
Integraciones de plugins de IDE para EmmyLua: - Idea - VSCode
El archivo ngx.d.lua en la raíz del proyecto proporciona algunos stubs de ngx.
Características soportadas
- Verificación de JWS: con claves simétricas o asimétricas.
- Desencriptación de JWE: con claves simétricas o asimétricas.
- Formato de claves asimétricas soportadas:
- PEM
- DER
- JWK
- Validación de claims de JWT.
- Recuperación automática de JWKS y validación de JWT.
- estrategias de caché opcionales.
- JWTs anidados (JWS en JWE)
Verificación de JWS
| Claims | Implementado |
|---|---|
| alg | |
| jku | |
| jwk | |
| kid | |
| x5u | |
| x5c | |
| x5t | |
| x5t#S256 | |
| typ | |
| cty | |
| crit |
| alg | Implementado | Requisitos de Implementación 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 |
Desencriptación de JWE
| Claims | Implementado |
|---|---|
| alg | |
| enc | |
| zip | |
| jku | |
| jwk | |
| kid | |
| x5u | |
| x5c | |
| x5t | |
| x5t#S256 | |
| typ | |
| cty | |
| crit |
| kty | Implementado | Requisitos de Implementación JOSE |
|---|---|---|
| EC | Recomendado+ | |
| RSA | Requerido | |
| oct | Requerido | |
| OKP | Opcional |
| alg | Implementado | Requisitos de Implementación 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 |
*La primera versión oficial de OpenResty que incluye OpenSSL 3.0+ es OpenResty 1.27.1.1 que se envió con OpenSSL 3.0.15 (Sí, la horriblemente lenta serie OpenSSL 3.0...).
Así que, por favor, usa OpenResty 1.27.1.2 como mínimo, que se envió con OpenSSL 3.4.1.
| enc | Implementado | Requisitos de Implementación JOSE |
|---|---|---|
| A128CBC-HS256 | Requerido | |
| A192CBC-HS384 | Opcional | |
| A256CBC-HS512 | Requerido | |
| A128GCM | Recomendado | |
| A192GCM | Opcional | |
| A256GCM | Recomendado |
Estrategias de caché para recuperación de JWKS
| Estrategia de Caché | Implementado |
|---|---|
| sin caché | |
| local (shared_dict) |
Uso de verificación de JWT
jwt.decode_header_unsafe
sintaxis: header, err = jwt.decode_header_unsafe(token)
Lee un encabezado jwt y lo convierte en una tabla de lua.
Importante: este método no valida la firma del JWT. Úsalo solo si necesitas inspeccionar el encabezado del token sin tener que realizar la validación 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
sintaxis: decoded_token, err = jwt.verify(token, secret, options?)
Valida un token JWS y lo convierte en una tabla de lua.
El parámetro opcional options se puede pasar para configurar el validador de tokens. Los campos válidos son:
- valid_signing_algorithms (dictalg permitidos usados para validar el JWT.
- typ (string | nil): si no es nulo, asegura que el claim JWT typ coincida con el valor pasado.
- issuer (string | nil): si no es nulo, asegura que el claim JWT iss coincida con el valor pasado.
- audiences (string | table | nil): si no es nulo, asegura que el claim JWT aud coincida con uno de los valores suministrados.
- subject (string | nil): si no es nulo, asegura que el claim JWT sub coincida con el valor pasado.
- jwtid (string | nil): si no es nulo, asegura que el claim JWT jti coincida con el valor pasado.
- ignore_not_before (bool): Si es verdadero, el claim JWT nbf será ignorado.
- ignore_expiration (bool): Si es verdadero, el claim JWT exp será ignorado.
- current_unix_timestamp (datetime | nil): los claims JWT nbf y exp serán validados contra esta marca de tiempo. Si es nulo,
se utilizará la fecha y hora actuales proporcionadas por ngx.time().
- timestamp_skew_seconds (int): Cuántos segundos de margen puede usar la biblioteca para verificar la expiración del token contra el tiempo actual. Útil cuando los relojes no siempre están sincronizados exactamente. Establecer este valor demasiado alto puede plantear problemas de seguridad.
Valores predeterminados para los campos de 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,
}
Ejemplo mínimo con claves 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
Ejemplo mínimo con claves asimé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
Ejemplos con 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"}, -- solo permitir algoritmos de la familia HS
audiences = {"user", "admin"}, -- `aud` debe ser uno de los siguientes
ignore_not_before = true -- ignorar el claim `nbf` (no 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
sintaxis: decoded_token, err = jwt.decrypt(token, secret, options?)
Desencripta y valida un token JWE y lo convierte en una tabla de lua.
El parámetro opcional options se puede pasar para configurar el validador de tokens. Los campos válidos son:
- valid_encryption_alg_algorithms (dictalg permitidos usados para desencriptar el JWT.
- valid_encryption_enc_algorithms (dictenc permitidos usados para desencriptar el JWT.
- typ (string | nil): si no es nulo, asegura que el claim JWT typ coincida con el valor pasado.
- issuer (string | nil): si no es nulo, asegura que el claim JWT iss coincida con el valor pasado.
- audiences (string | table | nil): si no es nulo, asegura que el claim JWT aud coincida con uno de los valores suministrados.
- subject (string | nil): si no es nulo, asegura que el claim JWT sub coincida con el valor pasado.
- jwtid (string | nil): si no es nulo, asegura que el claim JWT jti coincida con el valor pasado.
- ignore_not_before (bool): Si es verdadero, el claim JWT nbf será ignorado.
- ignore_expiration (bool): Si es verdadero, el claim JWT exp será ignorado.
- current_unix_timestamp (datetime | nil): los claims JWT nbf y exp serán validados contra esta marca de tiempo. Si es nulo,
se utilizará la fecha y hora actuales proporcionadas por ngx.time().
- timestamp_skew_seconds (int): Cuántos segundos de margen puede usar la biblioteca para verificar la expiración del token contra el tiempo actual. Útil cuando los relojes no siempre están sincronizados exactamente. Establecer este valor demasiado alto puede plantear problemas de seguridad.
- allow_nested_jwt (bool): Permite la verificación de JWTs que contienen otro JWT (también conocidos como JWTs anidados o jwt-in-jwt). Esto es opcional
por defecto, ya que los claims a validar siempre están dentro del JWT más interno y NO serán validados automáticamente. Depende de ti
validar recursivamente los JWTs internos devueltos como una cadena en el campo payload por esta biblioteca. Un JWT anidado DEBE contener la clave de encabezado cty configurada como JWT para ser reconocido como tal.
Valores predeterminados para los campos de 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,
}
Ejemplo mínimo con claves 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
Ejemplo mínimo con claves asimétricas en 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
Ejemplos con 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"}, -- solo permitir algoritmos de la familia A128KW (requiere OpenSSL 3.0+)
valid_encryption_enc_algorithms = {["A128CBC-HS256"]="A128CBC-HS256"}, -- solo permitir codificaciones de la familia A128CBC
audiences = {"user", "admin"}, -- `aud` debe ser uno de los siguientes
ignore_not_before = true -- ignorar el claim `nbf` (no 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 de verificación de JWKS
El módulo resty.jwt-verification-jwks implementa la recuperación automática de JWKS desde un endpoint HTTP y la posterior validación de JWT con las claves obtenidas.
Los módulos resty.jwt-verification-jwks-cache-* implementan estrategias de caché opcionales para JWKS. Solo se puede habilitar una estrategia de caché a la vez; si ninguna está habilitada, se llamará al endpoint de JWKS una vez por cada JWT a validar.
jwks.init
sintaxis: ok, err = jwks.init(cache_strategy?)
Inicializa el módulo jwks y opcionalmente especifica una estrategia de caché.
Esta función debe ser llamada solo una vez y preferiblemente en la sección init_by_lua_file.
local jwks = require("resty.jwt-verification-jwks")
-- inicializar sin caché
local ok, err = jwks.init(nil)
if not ok then
ngx.say("Error al inicializar el módulo jwks: ", err)
end
-- o ...
-- inicializar con caché local basado en el diccionario de memoria compartida de openresty.
-- agrega esto en la sección `http` de tu configuración de nginx: `lua_shared_dict resty_jwt_verification_cache_jwks 10m;`
-- ver 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("Error al inicializar el módulo jwks: ", err)
end
Puedes implementar tu propia caché y pasarla en el método init en su lugar. Aquí hay un ejemplo de cómo:
local my_cache = {}
--- Obtener la cadena de entrada en caché para la clave.
---@param key string Clave de caché.
---@return string|nil value Devuelve el resultado en caché como cadena si está presente, nil de lo contrario.
function my_cache.get(key)
-- TODO
end
--- Almacena datos bajo la clave hasta que expire.
---@param key string Clave de caché.
---@param value string Valor de caché.
---@param expiry integer Expiración de la entrada en caché en segundos.
---@return boolean|nil ok verdadero en caso de éxito
---@return string|nil err nil en caso de éxito, mensaje de error de lo contrario.
function my_cache.setex(key, value, expiry)
-- TODO
end
local ok, err = jwks.init(my_cache)
if not ok then
ngx.say("Error al inicializar el módulo jwks: ", err)
end
jwks.set_http_timeouts_ms
sintaxis: jwks.set_http_timeouts_ms(connect, send, read)
Establece los tiempos de espera del cliente HTTP en milisegundos utilizados para recuperar JWKS.
local jwks = require("resty.jwt-verification-jwks")
jwks.set_http_timeouts_ms(5000, 5000, 5000)
jwks.set_http_ssl_verify
sintaxis: jwks.set_http_ssl_verify(enabled)
Habilita/deshabilita la verificación TLS utilizada por el cliente HTTP para recuperar JWKS.
Por defecto, todos los certificados TLS son verificados. Si el endpoint de JWKS está utilizando certificados autofirmados, agrega la CA raíz respectiva al almacén de certificados del sistema operativo o desactiva la verificación de certificados con este endpoint (no es seguro).
local jwks = require("resty.jwt-verification-jwks")
jwks.set_http_ssl_verify(false)
jwks.set_cache_ttl
sintaxis: jwks.set_http_ssl_verify(enabled)
Cambia el TTL de caché predeterminado. El valor predeterminado es de 12 horas.
Nota: El ttl de caché solo se puede usar cuando el módulo jwks ha sido inicializado con una caché. Ver cómo habilitar la caché.
local jwks = require("resty.jwt-verification-jwks")
jwks.set_cache_ttl(2 * 3600) -- 2h
jwks.fetch_jwks
sintaxis: payload, err = jwks.fetch_jwks(endpoint)
Recupera manualmente JWKS desde un endpoint HTTP; el payload devuelto, en caso de éxito, es el cuerpo de la respuesta HTTP como cadena: No se realiza ninguna verificación de si el payload contiene JWKS o algo más.
Si se ha habilitado una estrategia de caché, el endpoint intentará recuperarlo primero de la caché. Después de un fallo en la caché y una recuperación exitosa de JWKS a través de HTTP, la caché se actualizará con el 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("error al recuperar 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
sintaxis: jwt, err = jwks.verify_jwt_with_jwks(jwt_token, jwks_endpoint, jws_options?)
Dado un jwt_token firmado como cadena, verifica su firma con JWKS proporcionados por el servicio HTTP encontrado en jwks_endpoint.
En caso de éxito, el JWT verificado se devuelve como una tabla de lua, de lo contrario, se devuelve nil y un error.
El parámetro opcional jws_options se puede pasar para configurar el validador de tokens al llamar a jwt.verify
después de haber recuperado exitosamente el JWKS. Consulta la documentación respectiva de jwt.verify para más información sobre qué opciones
se pueden pasar.
local jwks = require("resty.jwt-verification-jwks")
jwt, err = jwks.verify_jwt_with_jwks("<MI_JWT>", "http://myservice:8888/.well-known/jwks.json", nil)
if jwt == nil then
print("error al verificar jwt: ", err)
return
end
print(jwt.header.alg)
print(tostring(jwt.payload))
jwks.decrypt_jwt_with_jwks
sintaxis: jwt, err = jwks.decrypt_jwt_with_jwks(jwt_token, jwks_endpoint, jwe_options?)
Dado un jwt_token encriptado como cadena, desencríptalo con JWKS proporcionados por el servicio HTTP encontrado en jwks_endpoint.
En caso de éxito, el JWT desencriptado se devuelve como una tabla de lua, de lo contrario, se devuelve nil y un error.
El parámetro opcional jwe_options se puede pasar para configurar el validador de tokens al llamar a jwt.decrypt
después de haber recuperado exitosamente el JWKS. Consulta la documentación respectiva de jwt.decrypt para más información sobre qué opciones
se pueden pasar.
local jwks = require("resty.jwt-verification-jwks")
jwt, err = jwks.decrypt_jwt_with_jwks("<MI_JWT>", "http://myservice:8888/.well-known/jwks.json", nil)
if jwt == nil then
print("error al desencriptar jwt: ", err)
return
end
print(jwt.header.alg)
print(jwt.header.enc)
print(tostring(jwt.payload))
RFCs utilizados como referencia
- 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 Ejemplos de Protección de Contenido Usando Firmas y Encriptación de Objetos JSON (JOSE)
- Asignaciones de IANA JOSE
Ejecutar pruebas
Configuración
Instala el conjunto de pruebas:
sudo cpan Test::Nginx
Instala openresty: ver https://openresty.org/en/linux-packages.html
Ejecutar
export PATH=/usr/local/openresty/nginx/sbin:$PATH
prove -r t
Ejecutar benchmarks
El conjunto de pruebas Test::Nginx tiene integración de benchmarking incorporada con weighttp.
Aumentar límites de sysctl
Si planeas realizar pruebas de estrés en la biblioteca, es posible que necesites aumentar los límites del 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 cambios
sudo sysctl -p /etc/sysctl.d/openresty-benchmarks.conf
Lanzar pruebas
He creado algunos escenarios pseudo-reales dentro de la carpeta benchmarks.
## para más información sobre la sintaxis: https://openresty.gitbooks.io/programming-openresty/content/testing/test-modes.html
export TEST_NGINX_BENCHMARK='50000 10'
prove -r ./benchmarks
Por defecto, solo se utilizará 1 trabajador de nginx y 1 núcleo de CPU para realizar los benchmarks. Para aumentar los límites de trabajadores,
cambia la directiva workers(1); dentro de los archivos .t y vuelve a ejecutar el benchmark.
GitHub
Puedes encontrar consejos de configuración adicionales y documentación para este módulo en el repositorio de GitHub para nginx-module-jwt-verification.