Kong

Kong Gateway does not have a native external auth filter, but the pre-function plugin lets you run arbitrary Lua in the access phase and call Fairvisor Edge’s /v1/decision endpoint.

Plugin configuration (Deck / YAML)

plugins:
  - name: pre-function
    service: your-api-service    # or route: / global
    config:
      access:
        - |
          local http = require("resty.http")

          -- Build the original URI
          local path  = kong.request.get_path()
          local query = kong.request.get_raw_query()
          local uri   = query ~= "" and (path .. "?" .. query) or path

          -- Call Fairvisor Edge
          local client = http.new()
          client:set_timeout(200)   -- 200 ms
          local res, err = client:request_uri(
            "http://fairvisor-edge.default.svc.cluster.local:8080/v1/decision",
            {
              method = "POST",
              headers = {
                ["Authorization"]     = kong.request.get_header("authorization"),
                ["X-Original-URI"]    = uri,
                ["X-Original-Method"] = kong.request.get_method(),
                ["X-Forwarded-For"]   = kong.request.get_header("x-forwarded-for"),
              },
            }
          )

          if err then
            -- Fail-open: log error and continue
            kong.log.err("Fairvisor Edge unreachable: " .. err)
            return
          end

          if res.status == 429 then
            -- Propagate rate-limit headers to the caller
            local headers = res.headers
            kong.response.set_header("Retry-After",        headers["Retry-After"])
            kong.response.set_header("X-Fairvisor-Reason", headers["X-Fairvisor-Reason"])
            kong.response.set_header("RateLimit-Limit",    headers["RateLimit-Limit"])
            kong.response.set_header("RateLimit-Remaining",headers["RateLimit-Remaining"])
            kong.response.set_header("RateLimit-Reset",    headers["RateLimit-Reset"])
            return kong.response.exit(429, { message = "Rate limit exceeded" })
          end

Admin API (JSON)

curl -s -X POST http://localhost:8001/services/your-api/plugins \
  -H "Content-Type: application/json" \
  --data '{
    "name": "pre-function",
    "config": {
      "access": ["<lua-script-as-string>"]
    }
  }'

Fail-open vs fail-closed

The example above fails-open (continues if the edge is unreachable). To fail-closed, replace the kong.log.err block with:

if err then
  return kong.response.exit(503, { message = "Rate limit service unavailable" })
end

Passing custom descriptors

Any header you set before the Fairvisor call is available as a header:<name> descriptor key in your policy:

-- Set a pre-resolved tenant ID
kong.request.set_header("X-Tenant-ID", some_resolved_value)

Then in your policy:

{
  "limit_keys": ["header:x-tenant-id"],
  ...
}

Performance considerations

The pre-function plugin runs synchronously in the nginx worker. The Fairvisor call uses resty.http which is non-blocking (coroutine-based). Typical latency is under 1 ms for a local call; set the client:set_timeout to 200 ms to allow for outliers without stalling workers.

For high-throughput APIs, enable HTTP keepalive on the resty.http client:

local httpc = require("resty.http").new()
httpc:set_keepalive(60000, 100)  -- 60s idle timeout, max 100 connections