lua-resty-openidc
lua-resty-openidc copied to clipboard
Multiple public_keys?
Hello, I am using client credential grant flow and want to verify incoming tokens completely without connecting to my provider (Microsoft Entra, formerly known as Azure AD). Therefore I went to the JWKS URI and saw that they have two JWK entries with different x5c values and unfortunately Entra provides sometimes tokens signed with one OR the other key.
In lua-resty-openidc
opts
I can only set one public_key
as far as I know. I found out that an access token has an x5t
and kid
field that can be used to identify the right public_key (e.g. by a x5t to x5c mapping). I am using bearer_jwt_verify
, but to set opts.public_key
to the right one, I would need to get the access token before calling bearer_jwt_verify
, which would be rather unfortunate since this method does already do that here: https://github.com/zmartzone/lua-resty-openidc/blob/v1.7.6/lib/resty/openidc.lua#L1860 and I'd like to avoid doing it twice, especially as openidc_get_bearer_access_token
is a local function and hence I wouldn't be able to use it and would need to copy it into my own code.
Currently I am doing this, but this is O(n) and I want to get back to O(1).
local openidc = require("resty.openidc")
local function read_file(path)
local file = io.open(path, "r") -- r read mode
if not file then return nil end
local content = file:read "*a" -- *a or *all reads the whole file
file:close()
return content
end
local public_keys = {
read_file("/etc/nginx/config/jwkX5c.crt"),
read_file("/etc/nginx/config/jwkX5c2.crt"),
}
local entra_id_opts = {
token_signing_alg_values_expected = { "RS256" },
-- Available are: id_token, enc_id_token, user, access_token (includes refresh token).
session_contents = {access_token=true},
}
local _M = {}
function _M.validate_access_token()
local res, err
for _, public_key in ipairs(public_keys) do
entra_id_opts.public_key = public_key
res, err = openidc.bearer_jwt_verify(entra_id_opts)
if res and not err then
break
end
end
if err or not res then
ngx.status = 403
ngx.say(err and err or "no access_token provided")
ngx.exit(ngx.HTTP_FORBIDDEN)
end
end
return _M
Any idea how to deal with this? Or am I understanding something totally wrong? I am not sure how usual that is that a provider uses multiple JWK and returns different ones to the same client id.
Could this be a feature request that it is possible to provide this x5t to x5c mapping in opts
and the verification considers this?
Environment
- lua-resty-openidc version (1.7.6)
- OpenID Connect provider (Entra ID -> Azure AD)