Apache APISIX external authorization with forward-auth

Forward-auth lets APISIX send each request to your own authorization service before it reaches an upstream. This page explains the request and header flow, timeout and failure settings, and the latency and availability trade-offs to plan for.

On this page

When to delegate access decisions to your own auth service with forward-auth

Use forward-auth when the decision to allow or deny each request must live in an authorization service your organization already owns, such as an internal policy engine or an access service that your security team maintains, while APISIX stays the enforcement point at the edge. The forward-auth plugin sends each incoming request to that external service, which replies with an allow or deny result. By default the plugin issues a GET request to the authorization service, and you can set it to POST when the service needs the request body to decide. The plugin adds X-Forwarded headers so the service can see the original method, host, URI and client address, and it passes selected response headers from the authorization service on to the upstream or the client.

Most teams do not need this plugin. The built-in key-auth, jwt-auth and openid-connect plugins cover many cases with less moving code, and their sibling pages in this group cover those options. Forward-auth earns its place when the rules are too dynamic, too shared with other systems or too sensitive to copy into gateway configuration, for example when one policy engine must govern APIs, internal tools and data services together. Before you commit, confirm with your team which service will own the decision, who on-call will be when it fails, and whether the extra network hop on every request fits your latency budget. Measure that hop in your own environment, because the cost depends on where the authorization service runs relative to the gateway.

Forward-auth configuration options and when each fits

This table compares the main forward-auth settings a team chooses, from request method to failure behavior, and shows when each one suits the decision your auth service makes. Read each row as a question to answer before rollout, then confirm exact field names in the forward-auth documentation. The main takeaway is that the default timeout and failure code should be a deliberate choice, not an accepted default.

SettingDefault or optionWhen it fits
Request methodGET by default, POST forwards the request bodyUse GET when the decision depends only on headers, path and identity. Use POST when the auth service must read the request body to decide, and confirm body size limits first.
Authorization service URISet per route to your own auth endpointPoint it at a dedicated, internally reachable service so the decision path can be scaled and monitored separately from the upstream.
Forwarded request headersClient headers plus X-Forwarded headers added by the pluginForward only what the auth service needs to decide. Trim anything sensitive that the decision does not require, and confirm which headers the plugin adds by default.
Response headers passed onChosen auth response headers sent to the upstream or clientUse this to pass identity claims such as a user ID or role to the upstream. Pass only headers the upstream trusts, and strip any client-supplied copies of them.
Timeout3,000 ms by defaultKeep the default for fast in-cluster auth services. Lengthen it only after measuring the auth service's tail latency, since every request waits for this call.
Behavior on network errorsReturns 403 by defaultKeep fail-closed (403) for sensitive APIs. Consider a different failure response only after a documented risk review, because a permissive setting admits traffic while the auth service is unreachable.
Caching or degradation optionsConfirm availability in the current docsAsk whether the version you run supports any caching or degraded behavior, and test it before relying on it for production authorization.

Which headers the auth service receives and what reaches the upstream

The forward-auth plugin copies the incoming request to your authorization service, and the service's response decides what the upstream sees. For each request, APISIX sends a subrequest to the external auth endpoint, using GET by default. The plugin adds X-Forwarded-* headers describing the original request, such as the client address, host, method and URI, so the auth service can make a decision on the original call rather than on the gateway's internal hop. Your auth service should read the headers it needs from the original request, return a 2xx response to allow the call, and return a non-2xx response to deny it. Confirm the exact header names and the set of request headers copied in the forward-auth documentation for your APISIX version, and test them against a staging auth service before you write any policy that depends on them.

Response headers only reach the upstream when you name them in the plugin configuration. The upstream_headers setting selects which headers from the auth response, typically a user ID, email or group claim, are forwarded to the backend, and client_headers selects which ones are returned to the caller. Any header you do not list is dropped. The more important control is the reverse direction: if a client sends its own X-User-Id or similar header, that value must never reach your application unless APISIX overwrites it. Plan for the gateway to remove or replace every identity header that clients can send before forward-auth sets its own copy, and confirm this behavior for your routes, including any route that skips the plugin.

Treat identity-header trust as a control you prove, not a default. Before rollout, send requests from an external caller that include forged identity headers, test with and without the forward-auth plugin on each route, and check what the upstream logs or echoes back. Repeat the test after any change to route order, plugin priority or upstream header settings, and record the results as part of your change evidence. If your backend cannot be certain that identity headers came from APISIX, restrict it to accept traffic only from the gateway, using network policy or mTLS, so forged requests never reach it.

How to set up forward-auth on an APISIX route

This sequence takes a forward-auth check from an authorization service you already run to a tested APISIX route that allows, denies and fails closed as intended. The result is a route whose decisions and identity headers you have verified in a non-production instance before any client traffic depends on it.

  1. Confirm the authorization service and its endpoint

    The platform or security team that owns the authorization service confirms the URL APISIX will call, the HTTP method it expects (GET by default, or POST if the request body must be evaluated), and the exact status codes it returns for allow and deny. Send one manual request to that endpoint with the headers APISIX will forward and record the response. This step is done when the service returns the expected allow and deny codes for known test credentials and the team has written down which response headers it will send back for identity.

  2. Create a test route in a non-production instance

    The gateway engineer creates a route in a non-production APISIX instance, pointing at a simple test upstream that echoes the headers it receives. Keep the route isolated from production hostnames and consumers so that test traffic cannot reach real backends. Confirm the route answers requests through the data plane port before adding any plugin, so that a later failure can be attributed to forward-auth and not to basic routing.

  3. Enable forward-auth with the chosen method and headers

    Add the forward-auth plugin to the test route, set the authorization service URI, and choose the request method. List in the configuration which client request headers, such as Authorization or cookies, the service needs, and which response headers from the service should be copied to the upstream or client. Keep the list short, because every header you pass is a header the upstream will trust. The step is complete when the route configuration is saved and the Admin API returns it without errors.

  4. Set timeout and failure behavior

    Decide how the route should behave when the authorization service is slow or unreachable. The plugin's default timeout is 3,000 ms, and its default on network errors is to return 403, which fails closed. Confirm both values against your own service-level expectations and write them into the route configuration explicitly. Then stop the authorization service in the test environment and confirm that requests return the code you chose, not an allowed response.

  5. Verify denied requests return the service's code

    Send requests with credentials the authorization service rejects, and confirm that the client receives the same status code the service returned, and that the upstream logs show no request arrived. Repeat with a missing credential. A denied request that reaches the upstream, or that returns a different code from the one the service sent, means the route configuration or the plugin's response handling must be corrected before you continue.

  6. Verify allowed requests and identity headers upstream

    Send a request with valid credentials and confirm that it reaches the test upstream exactly once, with no duplicate requests in the upstream logs. Inspect the headers the echo upstream received and check that the identity headers you configured are present, carry the expected values for the test identity, and that no header from the client claiming a different identity survives. This step closes when the upstream log shows one request per client call with the correct identity values.

  7. Record the results before promoting the configuration

    Save the route configuration, the authorization service responses used in testing, and the results of each allow, deny and failure case in your change record. Ask the team that operates the gateway to confirm the latency added per request by measuring the same route with forward-auth enabled and disabled. Promote the configuration to production only after the change record shows every case passed and the upstream trusts only the headers you intended to pass.

How latency and failure settings affect availability

With forward-auth, every request that passes through the gateway waits for an extra network call to your authorization service before the upstream sees it. That cost is paid on the hot path of all protected traffic, not only on logins or token issuance, so the added time compounds with every hop. The location of the auth service therefore matters as much as its code. Placing it in the same network segment or availability zone as the gateway keeps the round trip short, while a service reached across regions or through a slow shared load balancer can dominate end-to-end response time.

  • Round trip per request: Each protected request makes one authorization call, so the added latency is the gateway-to-auth round trip plus the auth service's processing time.
  • Placement: Co-locate the auth service with the gateway where your network design allows it, and measure the call from the gateway's own network position.
  • Connection reuse: Confirm how the gateway reuses connections to the auth service, since repeated TLS handshakes add time on each call.
  • Tail latency: Measure the 95th and 99th percentile of the auth call, not only the average, because slow outliers set the user experience under load.
  • Load testing: Test with production-like request rates, since an auth service that is fast at low volume can queue at peak.

Before go-live, ask your team to measure the added latency per route under realistic peak load and to record the auth service's own capacity limits.

Security and operational risks of delegated authorization

Forward-auth puts an external service in the path of every request the gateway handles, so the risks cluster around three questions: who can be believed about identity, who can reach the decision endpoint, and how the decisions are recorded and kept fast. The cards below cover each area as it applies to APISIX forward-auth specifically.

Header spoofing at the trust boundary

Forward-auth copies selected headers from the authorization service's response to the upstream or client, so the upstream trusts whatever arrives there. Strip any identity headers a client can send before the auth step runs, and confirm that only the headers you explicitly list are forwarded. Test by sending a request with a forged identity header through the gateway and checking that the upstream sees only the value your auth service returned.

Locking down the auth endpoint

The authorization service should accept calls only from APISIX nodes. Place it on a private network segment or behind a policy that allows the gateway's addresses alone, and use TLS on the connection if it crosses a network boundary you do not fully control. An exposed decision endpoint lets any caller probe your policy or send forged subrequests that the service may accept as coming from the gateway.

Audit logging of allow and deny decisions

Record each allow and deny decision with the route, the consumer or subject identifier, the time and the reason returned by the auth service. Keep the gateway access log and the auth service log correlated through a shared request ID, so an investigator can tie a denied call to the policy version that produced it. Ask your auth team which fields they log and where the logs are retained, because the gateway log alone rarely records why a request was refused.

Capacity and monitoring of the auth service

The auth service sits on every protected request, so its latency and error rate become the gateway's latency and error rate. Monitor response time percentiles, error counts and timeouts from the auth service side, and set capacity against your peak request rate with headroom. Plan the behavior when the service is slow or unavailable: the default timeout and the 403 response on network errors decide whether a brief outage blocks all protected traffic.

Forward-auth questions buyers ask before hiring help

How much effort does a forward-auth setup take and what drives it?

Effort depends mostly on the number of routes that need the check, how mature your existing auth service is, how precisely the header contract is defined, and how much testing the rollout needs. A single route protected by an auth service that already returns clear allow and deny responses is a small change. Ten routes with different policies, an auth service that has not been load tested, and no written list of the headers passed upstream are a much larger job. Ask any partner to break the quote into design of the header contract, gateway configuration, failure-mode testing and rollout, so you can see which driver dominates your case.

Can our team set up APISIX forward-auth on its own?

Yes, if you have engineers who can run APISIX in your infrastructure, write route and plugin configuration, and test denials and timeouts against a real auth service. Many teams do the first routes themselves and bring in help for the parts that are easy to get wrong: the header trust model, what happens when the auth service is slow or down, and how the check is tested before traffic moves. Be honest about who will own the configuration after go-live, because forward-auth decisions sit on the request path of every protected route.

What does the work need from our side?

The work needs named owners for the auth service and its API contract, network access between the gateway and the auth service, and TLS settings that both sides accept. You also need test identities for each role or consumer type, including accounts that should be denied, so that denials are verified and not assumed. Plan for someone who can confirm which response headers the upstream services already trust, because forward-auth can pass identity headers to them. Ask the partner to list these inputs in the written scope so gaps show up before the build starts.

Should we use forward-auth, openid-connect or jwt-auth?

The choice depends on where the identity decision should live. Use jwt-auth when your own services issue JWTs that APISIX can verify locally. Use the openid-connect plugin when an identity provider should handle login or token validation for browser or API clients. Use forward-auth when your existing auth service already holds the authorization logic and you want the gateway to ask it on each request. Forward-auth adds a network call to every request, so compare its latency and failure behavior with the alternatives. The APISIX forward-auth plugin documentation describes the request and response behavior you will need to design around.

How long does a forward-auth pilot take?

A pilot's length depends on how many routes it covers, whether the auth service already has the response contract the gateway needs, how many failure cases you test, and how quickly your change process approves configuration. A pilot on one non-critical route with an existing auth service is much shorter than a pilot covering several production routes with timeout and degradation tests. No duration can be stated before the scope is written. Ask for a schedule with milestones tied to the routes, test cases and approvals in that scope, not a generic estimate.

What does a fixed-scope quote cover?

A fixed-scope quote follows from a written scope that lists the routes in scope, the auth service and its contract, the header rules for upstreams, timeout and failure-code settings, the test cases, the deliverables and the timeline. It should state what the client provides, such as access and test identities, and what is excluded, such as changes to the auth service itself. DeployOpen does not publish a price list, so the quote is produced from that scope. Ask whether the quote covers one-time build work only, and whether ongoing support or upgrades are a separate retainer.

Running forward-auth after go-live

Once forward-auth is live, the auth service sits on the path of every request it protects, so its health is the gateway's health. Monitor the authorization service's response times and error rates separately from gateway latency, and set alerts for both. Track how often the plugin returns 403 because the auth service was unreachable or timed out, since the default behavior fails closed and a silent auth outage looks like a wave of denied users. Compare those counts with your auth service's own logs to confirm that the failures start where you expect. Confirm with your gateway team which access logs and metrics your APISIX build exposes for the plugin, because the exact metric names depend on the version and observability plugins you enable.

Changing authorization rules should not require editing every route. Keep the decision logic in your auth service and treat the forward-auth settings on the route (the auth URI, the headers you pass through, and the timeout) as stable configuration that changes rarely. Confirm the operational path for your deployment mode before you plan any change. In traditional mode, changes go through the Admin API to the etcd cluster. In decoupled mode, the control plane publishes changes that the data plane picks up. In standalone mode, the configuration lives in conf/apisix.yaml or conf/apisix.json, which APISIX checks for changes every second and hot-reloads. Ask your team who is allowed to change the file or the Admin API, and whether those changes go through version control and review.

Plan rollback before the first change. Keep the previous plugin configuration in version control or a backup you can apply quickly, and rehearse restoring it in a non-production environment. Under standalone mode, rollback usually means restoring the previous file version and letting the reload take effect, which you should time and verify. Under traditional and decoupled modes, confirm how the Admin API or your automation reverts a route, and whether the revert reaches every gateway node. After any rollback, run a set of allowed and denied test requests against the protected routes and check the upstream logs to confirm that the identity headers match what the auth service returned.

How DeployOpen works on this

DeployOpen plans, implements, tests and documents Apache APISIX external authorization with forward-auth inside your own infrastructure. We start from the decision your auth service must make on each request, then build and verify the gateway configuration around it, so your team can operate it after handover.

How we scope

  • We agree in writing which routes use forward-auth and which stay on other authentication plugins.
  • The written scope names your auth service, the headers it returns, and the upstreams that receive identity headers.
  • We record the timeout, failure code and degradation behavior you choose for each route before build starts.
  • Engagements are fixed-scope, so deliverables and timelines are agreed in writing before work begins.

How we build

  • We configure the forward-auth plugin with the request method, forwarded headers and response headers you define.
  • We test allow, deny and unreachable-service paths against your auth service in a non-production environment.
  • We measure added latency per request on representative routes and report results to your team.
  • We validate identity header stripping and pass-through so upstreams cannot receive spoofed values from clients.

How we hand over

  • You receive route and plugin configuration as files, with a record of each decision and its reason.
  • Runbooks cover timeout tuning, failure codes, degradation settings and rollback steps for your operators.
  • We walk your platform, security and application teams through the test results and open risks.
  • Ask us to confirm which configuration lives in your repository and which parts your team owns after handover.

How we support

  • Ongoing support, upgrades and continuous testing are available as retainers after the initial delivery.
  • A retainer can cover APISIX version upgrades, plugin behavior changes and periodic re-testing of authorization paths.
  • Support scope and response arrangements are set out in the written agreement, so ask for them during quoting.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.