0

We're trying to run a lua script to hook into fixups phase of a request in an apache server app, but we keep getting the following:

"[Thu Aug 28 09:55:37.099004 2025] [lua:crit] [pid <<pid>>] [client <<IP>>] <redacted>: lua: Unable to find function fetch_token_hook in /var/www/html/<<app domain>>/lua/fetch_token.lua, referer: https://<<app domain>>/?<<query parameters>>"

This how is the apache config file is currently defined, only including the relevant details:


  ## Vhost docroot
  DocumentRoot "/var/www/html/<<app domain>>"

  ## Directories, there should at least be a declaration for /var/www/html/<<app domain>>

  <Directory "/var/www/html/<<app domain>>">
    AllowOverride None
    Require all granted
  </Directory>

 ## Custom fragment
  # Lua config
LoadModule lua_module modules/mod_lua.so
LuaHookFixups /var/www/html/<<app domain>>/lua/fetch_token.lua fetch_token_hook
<Files "*.lua">
  SetHandler lua-script
</Files>

And this is what the lua script looks like:

local http   = require "socket.http"   
local ltn12  = require "ltn12"
local cjson  = require "cjson"

local token_endpoint = "<redacted>"
local client_id      = "<redacted>"
local client_secret  = "<redacted>"
local scope          = "<redacted>"   

local cached_token   = nil
local expires_at     = 0        

local function get_new_token(r)
  local body = string.format(
      "grant_type=client_credentials&client_id=%s&client_secret=%s&scope=%s",
      client_id, client_secret, scope:gsub(" ", "%%20"))

  local resp_chunks = {}
  local _, code = http.request{
    url     = token_endpoint,
    method  = "POST",
    headers = {
      ["Content-Type"]   = "application/x-www-form-urlencoded",
      ["Content-Length"] = #body
    },
    source  = ltn12.source.string(body),
    sink    = ltn12.sink.table(resp_chunks)
  }

  if code ~= 200 then
    r:err("[lua] token endpoint returned status "..tostring(code))
    return nil
  end

  local token_json = table.concat(resp_chunks)
  local t = cjson.decode(token_json)

  if not t.access_token or not t.expires_in then
    r:err("[lua] token endpoint did not return access_token / expires_in")
    return nil
  end

  cached_token = t.access_token
  expires_at   = os.time() + tonumber(t.expires_in)
  return cached_token
end

function fetch_token_hook(r)
  file = io.open("/var/www/html/<<app domain>>/lua/lualog.txt","a")
  file:write("Start of log \n")
  file:write(r.uri)
  file:write("\n <End of log>")
  file:close()

  if not r.uri:match("^<<proxy path>>") then
    return apache2.DECLINED
  end

  if (not cached_token) or (os.time() > expires_at - 30) then
    if not get_new_token(r) then
      return apache2.HTTP_INTERNAL_SERVER_ERROR
    end
  end

  r.headers_in["Authorization"] = "Bearer "..cached_token

  return apache2.DECLINED 
end

We've double and triple checked the path and the naming and we've been able to get this exact setup running locally, so we know it's not typo. At this point we're almost convinced it's some kind of security issue, but we can't see any holes there either. These are the permissions granted to the fetch_token.lua file:

"-rwxr-xr-x. 1 <<user>> www 1834 Aug 29 09:33 fetch_token.lua"

We've also tried:
- Tried incorrect lua script path (still says it can't find the method, might be an indication that directive can't find the script with even the correct path)

- Tried removing LoadModule lua_module modules/mod_lua.so (As expected, gives an error indicating lua isn't available)

- Added file tags for loading script (No difference)

- Tried simplifying lua script (no difference)

- Tried running lua script manually (It works)

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.