Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple public_keys? #512

Open
renedupont opened this issue Mar 28, 2024 · 0 comments
Open

Multiple public_keys? #512

renedupont opened this issue Mar 28, 2024 · 0 comments

Comments

@renedupont
Copy link

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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant