Skip to main content

Extending the APISIX Plugin

Goal

Understand the Keymate APISIX access plugin — its dual implementation model, configuration parameters, request flow, and extension points — so you can customize its behavior for your deployment.

Audience

Developers integrating Keymate authorization into Apache APISIX routes, or customizing the plugin behavior for specific use cases.

Prerequisites

  • A running Apache APISIX instance (version 3.10.0 or later)
  • Access to a running Access Gateway instance
  • Familiarity with Apache APISIX route and plugin configuration
  • For WASM modifications: Go and TinyGo 0.33.0
  • For Lua modifications: basic Lua and OpenResty knowledge

Before You Start

The Keymate APISIX plugin ships in two implementations:

ImplementationLanguageRuntimeBest For
LuaLua (native APISIX plugin)OpenRestyStandard deployments, fast iteration, no compilation step
WASMGo (compiled with TinyGo)WASM VM via proxy-wasmHigh-performance isolation, language-neutral execution

Both implementations perform the same function: intercept incoming HTTP requests during the APISIX access phase, forward them to the Access Gateway for authorization, and allow or deny the request based on the response.

The Lua plugin is registered as keymate-access-gateway in APISIX with priority 2000. The WASM plugin uses the proxy-wasm Go SDK (github.com/tetratelabs/proxy-wasm-go-sdk).

Choose the implementation that fits your operational requirements. Both can run simultaneously on different APISIX routes.

Worked Example

In this guide, you configure the plugin on a route, understand how the request flows through the authorization check, and learn where to extend the plugin behavior.

Steps

1. Understand the request flow

When a client request hits an APISIX route with the Keymate plugin enabled, the following sequence occurs:

The plugin:

  1. Captures the original request headers, method, URI (path + query string), and body
  2. Removes protected headers to prevent client-side spoofing (Keymate-Enforcer, Keymate-Target-URI, Keymate-Target-Method)
  3. Adds Keymate-specific headers identifying the gateway enforcer, target URI, and HTTP method
  4. Sends a POST request to the Access Gateway with the original request body
  5. Interprets the Access Gateway response: 2xx means allow, anything else means deny

2. Configure the Lua plugin

The Lua plugin is configured in the APISIX route definition:

APISIX route configuration (Lua)
plugins:
keymate-access-gateway:
gateway_url: "http://access-gateway.example.com:8080"
endpoint: "/gateway/api/v1/access/plugins/check-permission"
timeout: 5000

Configuration parameters:

ParameterTypeRequiredDefaultDescription
gateway_urlStringYesBase URL of the Access Gateway instance
endpointStringNo/authAuthorization endpoint path appended to gateway_url
timeoutIntegerNo5000Request timeout in milliseconds

The Lua plugin uses APISIX's resty.http client with connection keepalive (60s timeout, pool size 100).

3. Configure the WASM plugin

The WASM plugin accepts configuration as a JSON string in the conf parameter:

APISIX route configuration (WASM)
plugins:
keymate-access-gateway-wasm:
conf: |
{
"gateway_url": "http://access-gateway.example.com:8080",
"endpoint": "/gateway/api/v1/access/plugins/check-permission",
"timeout": 5000
}

The WASM plugin accepts the same parameters as the Lua plugin (gateway_url, endpoint, timeout) with the same defaults.

4. Understand the headers

Headers set by the plugin (sent to Access Gateway):

HeaderValueDescription
Keymate-Enforcerlayer="gateway", tech="apisix", version="<plugin-version>"Identifies the enforcer type, technology, and version
Keymate-Target-URIOriginal request path and query stringThe target URI for access rule matching
Keymate-Target-MethodOriginal HTTP methodThe HTTP method for resource resolution

Headers filtered (not forwarded to Access Gateway):

The plugin removes these headers from the forwarded request to prevent client-side spoofing:

  • Keymate-Enforcer — always set by the plugin
  • Keymate-Target-URI — always set by the plugin
  • Keymate-Target-Method — always set by the plugin
  • Content-Length — recalculated for the gateway request

All other original request headers (including Authorization and Keymate-Client-Id) are forwarded as-is.

Headers added to the client response:

HeaderSourceDescription
Keymate-DecisionAccess GatewayAuthorization decision result and authority source
Keymate-Decision-LatencyAccess GatewayTotal decision processing time in milliseconds
Keymate-Decision-Authority-LatencyAccess GatewayAuthority call latency in milliseconds
Keymate-Decision-CacheAccess GatewayCache hit or miss indicator
Keymate-GatewayAccess GatewayAccess Gateway version
Keymate-Gateway-Auth-DurationPluginTotal plugin execution time in milliseconds
Keymate-Gateway-Auth-StatusPluginPlugin outcome: GRANTED, DENIED, or GATEWAY_FAILED
note

Keymate-Decision-* and Keymate-Gateway headers are forwarded from the Access Gateway response. Keymate-Gateway-Auth-Duration and Keymate-Gateway-Auth-Status are set by the plugin itself to track total plugin execution time and the final authorization outcome.

5. Understand error handling

ConditionHTTP StatusResponse BodyKeymate-Gateway-Auth-Status
Access Gateway unreachable or timeout502{"error": "Authorization Service Unavailable"}GATEWAY_FAILED
Access Gateway returns 2xxRequest forwarded to upstreamGRANTED
Access Gateway returns 4xxSame as gatewayGateway response body forwarded to clientDENIED
Access Gateway returns 5xxSame as gatewayGateway response body forwarded to clientGATEWAY_FAILED

The plugin does not retry failed gateway requests. If the Access Gateway is unavailable, the request is rejected with a 502 status.

note

The WASM plugin also includes backward compatibility with legacy Access Gateway header names (Elapsed-Time-MsKeymate-Decision-Latency, Permission-Gateway-Duration-MsKeymate-Decision-Authority-Latency). New headers take priority when both are present.

6. Customize per-route behavior

Configure different plugin parameters per APISIX route. This allows different services behind the same APISIX instance to use different Access Gateway endpoints or timeouts:

Route-specific configuration
routes:
- uri: /api/payments/*
plugins:
keymate-access-gateway:
gateway_url: "http://access-gateway.example.com:8080"
endpoint: "/gateway/api/v1/access/plugins/check-permission"
timeout: 3000

- uri: /api/reports/*
plugins:
keymate-access-gateway:
gateway_url: "http://access-gateway.example.com:8080"
endpoint: "/gateway/api/v1/access/plugins/check-permission"
timeout: 10000

7. Extend the plugin

To add custom behavior, modify the plugin source code:

Adding custom headers: Both implementations construct the gateway request headers in a central location. Add new headers alongside the existing Keymate-* headers to pass additional context to the Access Gateway.

Adding protected headers: Expand the protected_headers table (Lua) or the header filter conditions (WASM) to prevent additional client-supplied headers from reaching the Access Gateway.

Custom error responses: Modify the error handling section to return custom error formats or status codes when the Access Gateway is unavailable.

Custom logging: Both implementations include log points for debugging. The Lua plugin uses core.log.info/core.log.warn/core.log.error. The WASM plugin uses proxywasm.LogInfof/proxywasm.LogWarnf/proxywasm.LogErrorf.

warning

After modifying the Lua plugin, reload the APISIX configuration. After modifying the WASM plugin, recompile with TinyGo (make build) and redeploy the WASM binary.

Validation Scenario

Scenario

You configure the Lua plugin on a route and send a request with a valid access token. The Access Gateway grants access and the request reaches the upstream service.

Expected Result

  1. The upstream service receives the request
  2. The client response includes Keymate-Decision and Keymate-Gateway-Auth-Duration headers
  3. Keymate-Gateway-Auth-Status is GRANTED

How to Verify

  • API evidence: Send a request with a valid Bearer token and check the response headers for Keymate-Decision, Keymate-Decision-Cache, and Keymate-Gateway-Auth-Status
  • Logs: Check APISIX error logs for [KEYMATE-ACCESS-GATEWAY] plugin execution entries
  • Audit evidence: Verify the Access Gateway audit log contains the authorization check event

Troubleshooting

  • 502 "Authorization Service Unavailable" — The plugin cannot reach the Access Gateway. Verify the gateway_url is correct and the Access Gateway is running. Check network connectivity between APISIX and the Access Gateway.
  • Timeout errors — Increase the timeout value in the plugin configuration. The default is 5000ms. For latency-sensitive deployments, ensure the Access Gateway is co-located in the same network.
  • Client-supplied Keymate headers are ignored — This is by design. The plugin filters Keymate-Enforcer, Keymate-Target-URI, and Keymate-Target-Method from client requests to prevent spoofing.
  • WASM plugin not loading — Verify the WASM binary is compiled and accessible by APISIX. Rebuild with make build and ensure the binary path matches the APISIX plugin configuration.
  • Missing decision headers in response — The Access Gateway may not be returning decision headers. Verify the Access Gateway version supports the expected response headers. Check for the backward-compatible legacy header names.

Next Steps

Set up a local development environment to test plugin changes — see Plugin Local Development & Test Setup.

For contributing changes back to the plugin repository, see Contributing to Enforcement Plugins.