Introspection or local JWKS: which way APISIX should validate your access tokens
The choice for an API team is between asking the identity provider about each token on every request (introspection) and verifying the token's signature inside APISIX using a public key or JWKS (local verification). By default, the APISIX openid-connect plugin validates bearer tokens through the provider's introspection endpoint. Setting public_key or use_jwks switches the plugin to local signature checks and skips introspection. Introspection fits when you need the provider's answer on each request, for example when a token may be revoked before it expires and that revocation has to take effect at the gateway. Local verification fits when latency and provider load matter more, because the gateway then depends on the provider only for the public keys it caches, not for every call.
Before you pick a path, confirm three things in your own environment. First, whether your provider exposes a discovery document and a JWKS endpoint that APISIX can reach, since the discovery document drives the plugin's behavior. Second, how your tokens are issued (signing algorithm, audience values and issuer string), because local checks only work if those match what the plugin is configured to expect. Third, your revocation requirements, since a locally verified token stays valid until its expiry unless you add a separate control. The APISIX changelog shows that recent releases tightened this area: APISIX 3.18.0 made bearer introspection fail closed when the discovery document is unavailable, and APISIX 3.19.0 rejects introspection responses whose iss does not match valid_issuers. Read the APISIX openid-connect plugin documentation against your target version before you commit to either design.
Whichever path you choose, test the failure modes before rollout. Stop the provider or block the discovery endpoint in a test environment and confirm that APISIX rejects requests instead of passing them through. Send tokens with the wrong aud, a foreign iss, and a missing scope, and confirm each returns a denial. Note that ssl_verify defaults to true from APISIX 3.16.0, so certificate problems in your identity provider connection will surface as failures unless you have configured a trusted chain. Record the chosen mode, the issuer and audience settings and the expected behavior on provider outage in your design document, because those are the settings an auditor or on-call engineer will ask about first.
How revocation, latency and provider dependency change the choice
Introspection and local JWKS verification fail in different ways. The cards below cover where each path sees revocation, what it costs per request, how it behaves when the identity provider is down, and what each can see inside a token.
Revocation timing
Introspection asks the identity provider whether a token is still active, so a revoked session or disabled user is refused on the next call. Local signature checks only prove the token was signed by a trusted key and has not expired, so a revoked token keeps working until its lifetime ends. Ask your team how long access tokens live, whether revocation must take effect within seconds, and whether a short token lifetime with refresh is an acceptable substitute.
Per-request latency and provider load
Introspection adds a round trip to the identity provider on requests that are not cached, so every gateway node multiplies the load on the provider. Local verification checks a signature in the gateway process and avoids that call. Measure the introspection response time from your gateway network, estimate peak request rates, and confirm whether the plugin caches introspection results and for how long in your configured version.
Identity provider availability
With introspection, a provider outage or network partition can block every protected API that depends on it. Local JWKS verification keeps working while the provider is down, as long as the cached keys remain valid. Decide whether your APIs should stay available during a provider incident, and confirm how the plugin behaves when the discovery document or keys cannot be fetched in the version you plan to run.
Key rotation handling
Local verification depends on the gateway knowing the provider's current signing keys. When the provider rotates keys, a stale cache rejects valid tokens, and an overly permissive refresh can accept tokens signed by keys you no longer trust. Document how keys are fetched and refreshed, who is alerted on signature failures, and how a planned rotation is tested in staging before it reaches production.
Visibility into token contents
Introspection returns the provider's view of the token, including whether it is active and its current claims, so policy can reflect the latest state. Local checks read only what is inside the signed token, which can be stale and may omit claims the gateway needs. Map the claims your routes depend on, such as issuer, audience, scope and subject, and confirm each one is present in the access token your provider issues.
Issuer and audience enforcement
Both paths need checks that the token came from the expected issuer and was meant for this API. Recent APISIX releases add audience, issuer and required scope enforcement to bearer introspection, and reject responses whose issuer does not match the configured list. Test with tokens minted for other APIs and other issuers, and confirm the behavior of your target version before relying on it.
Configuring introspection, JWKS and public key verification
When the openid-connect plugin receives a bearer token and no local verification option is set, it sends the token to the identity provider's introspection endpoint and accepts the request only if the provider reports the token as active. The provider stays the authority on every request, so a revoked or expired token is rejected as soon as the provider reports it inactive. The cost is one outbound call per request, or per cached result, which adds latency and a dependency on the provider's availability.
- Discovery and client credentials: APISIX needs the provider's discovery document URL, a client ID and a client secret so it can authenticate its introspection call. Confirm that the client is allowed to introspect tokens in your provider.
- Bearer-only mode: Settings such as
bearer_onlytell the plugin to reject requests without a valid bearer token instead of starting a login redirect. Use this for APIs, not for browser logins. - Audience and issuer checks: In 3.18.0 and later, check that
aud,issand required scopes are enforced for introspected tokens, and confirm the issuer string matches what your provider puts in tokens. - Fail-closed behavior: From 3.18.0, bearer introspection fails closed when the discovery document cannot be fetched. Plan for the provider being unreachable, since requests will be rejected during that time.
- TLS to the provider:
ssl_verifydefaults to true from 3.16.0, so the gateway checks the provider's certificate chain. Confirm that your provider's certificate chains to a CA the gateway trusts before upgrading.
Before going live, confirm with your identity provider that introspection is enabled for the client and that the response includes the claims your routes depend on.
With use_jwks enabled, APISIX fetches the signing keys published by the provider's JWKS endpoint and verifies each JWT signature locally. Introspection calls are skipped, so the provider is not contacted on each request, and the gateway can keep serving tokens during short provider outages as long as the keys remain cached. The trade-off is that revocation is delayed until the token expires, because a locally valid signature stays valid.
- Key settings:
use_jwksis the switch that enables local verification. The plugin then reads the JWKS URI from the discovery document, so the discovery URL and the provider's key rotation behavior both matter. - Key rotation: Confirm how often your provider rotates signing keys and that the new
kidappears in the JWKS before tokens signed with it are issued. - Algorithm and issuer: Confirm which signing algorithm your provider uses, and set the issuer and audience checks so tokens from other tenants or applications are rejected.
- Token lifetime: Because revocation is not checked, shorter access token lifetimes at the provider reduce the window in which a revoked token still works.
- TLS to the JWKS endpoint: The JWKS fetch uses the same
ssl_verifybehavior, so the provider's certificate must be trusted by the gateway.
Confirm with your provider the JWKS URI, the rotation schedule and the token lifetime, then test a rotated key in a non-production route before relying on it.
Setting public_key gives APISIX a fixed PEM public key to verify token signatures without any network call to the provider. This suits environments where the provider's JWKS endpoint cannot be reached from the gateway, or where the signing key is managed as a controlled artifact. It removes the dependency on discovery at request time, but every key change becomes a configuration change that someone must make and test.
- Key management: The public key must match the provider's signing key exactly. Store it in your configuration system and track its version, since a stale key causes every request to fail verification.
- Rotation process: Plan a change window in which the new key is added and the old one is retired, because a single key value does not follow provider rotations automatically.
- Claim checks still apply: Signature checks do not cover issuer, audience, expiry or scope. Configure those checks explicitly, as with the other modes.
- Revocation: A static key gives no revocation signal. Pair it with short token lifetimes and, where your risk model requires it, a separate revocation control.
- Air-gapped and restricted networks: This option works where the gateway cannot reach the provider at all, provided the key and the token issuance process are both controlled.
Before choosing this mode, ask your provider how keys are rotated and whether your team can receive rotation notices in time to update the gateway.
Which openid-connect settings control token validation and when each fits
This table maps the openid-connect plugin settings that decide how APISIX validates access tokens to the situations where each one fits. Read each row as a question to answer for your identity provider and token format before you choose between introspection and local signature checks.
| Setting | What it controls | When it fits | What to confirm |
|---|---|---|---|
| discovery | URL of the provider's OpenID configuration document, used to locate endpoints such as introspection and keys | Any setup where APISIX should resolve endpoints from the provider rather than hard-coding them | Discovery is reachable from the gateway network and returns the expected issuer value |
| public_key | A PEM public key that APISIX uses to verify JWT signatures locally, skipping introspection | Fixed signing key with a small number of rotations, and no need for per-request calls to the provider | Who rotates the key, how the new key reaches every gateway node, and what happens during rotation |
| use_jwks | Fetches the signing keys from the provider's JWKS endpoint and verifies JWT signatures locally | Providers that rotate keys regularly and publish a JWKS endpoint, with access tokens in JWT format | Tokens are JWTs, the JWKS endpoint is reachable, and how long key caches last before rotation takes effect |
| introspection_endpoint and client credentials | Endpoint and client ID and secret APISIX uses to ask the provider whether a token is active | Opaque tokens, or JWTs where revocation must be checked on every request | Latency added per call, load the provider can absorb, and where the client secret is stored |
| required_scopes | Requires listed scopes on the token; returns 403 when scopes are missing | Routes that need a specific permission level in addition to a valid token | Scope names match what the provider issues, and clients request them in their token request |
| claim_validator | Checks claims such as issuer and audience against expected values | Multi-audience APIs or shared providers where tokens for other services must be refused | Exact issuer string, including trailing slashes, and the audience value each API expects |
| valid_issuers | Lists issuers that introspection responses may carry, rejected when iss does not match | Environments with more than one issuer URL, such as a custom domain alongside the default | Every issuer URL the provider can emit, and that the list is updated after any provider domain change |
| ssl_verify | Whether APISIX verifies the TLS certificate of the provider when calling discovery, JWKS or introspection | Any production call to an identity provider over HTTPS, including private certificate authorities | Certificate chain trust in the gateway, since the default changed to true in APISIX 3.16.0 |
How issuer and audience checks close the gap in both paths
A valid signature or a successful introspection response does not prove that a token was meant for this API. Either path can confirm that a token is genuine and current while the token was issued by a different authorization server or minted for a different client or resource. In the openid-connect plugin, the claim_validator setting is where you close that gap. Configure it to check the iss claim against the issuer you trust and the aud claim against the audience your gateway represents, and treat any mismatch as a rejection. Pair it with required_scopes, which returns a 403 when a token lacks the scopes a route needs, so that a valid token with too little authority is refused at the gateway rather than reaching the upstream.
APISIX 3.18.0 tightened this for bearer introspection. According to the APISIX changelog, that release enforces audience, issuer and required scopes on the introspection path and makes the plugin fail closed when the discovery document is unavailable. Check your version before you rely on this behavior, and test that a token with the wrong audience or missing scope is denied on each route you protect. APISIX 3.19.0 then rejected introspection responses whose iss does not match the configured valid_issuers, which matters when the identity provider returns a response for a different realm or tenant than you expect. Confirm the exact valid_issuers values with your identity provider, including trailing slashes and tenant identifiers, because a mismatch will block legitimate traffic.
The practical step is to write the expected issuer, audience and scope set down per route before you choose a verification path, and then test negative cases for both paths: a token from another issuer, a token for another audience, and a token without the required scope. Use the APISIX openid-connect plugin documentation to confirm the field names and defaults for your release. These checks are the same in introspection and local JWKS verification, so the choice between them should rest on revocation and latency needs rather than on which one enforces the claims.
Setup sequence for a validated OIDC route in APISIX
This sequence takes an OAuth access token from identity provider registration through a tested APISIX openid-connect route, with a chosen validation path, checked issuer, audience and scope rules, and a recorded gateway version. Each step closes with a check that the team can repeat before go-live.
Register the API as a resource at the identity provider
The identity team creates a resource or audience for the API at the identity provider, such as a Keycloak client scope or an Entra ID app registration, and defines the scopes that clients may request. The API owner confirms the exact audience string and the scope names, because the gateway will compare against them. Done when a test client can obtain an access token whose aud and scope claims match the values written down for the route.
Confirm discovery and key endpoints
The platform team opens the provider's OpenID discovery document and confirms the issuer value, the introspection endpoint, and the JWKS URI. They check that each URL is reachable from the APISIX data plane network, not only from a workstation, and that TLS certificates validate. Done when a request from a gateway node returns the discovery document and the key set, and the issuer string matches the one in the token exactly.
Pick the validation path
The security architect chooses between introspection calls to the provider on every request and local signature checks against JWKS or a configured public key. The decision record should cover revocation expectations, the latency budget, the load the provider can absorb, and whether tokens are opaque or JWTs. The openid-connect plugin uses introspection by default, and setting public_key or use_jwks switches to local verification. Done when the chosen path and its trade-offs are written into the route design record.
Configure issuer, audience and scopes
The platform engineer adds the openid-connect plugin to the route and sets the discovery URL, client settings, and the validation path chosen in the previous step. They then configure the issuer and audience checks through claim validation and list the scopes in required_scopes, so that tokens missing a scope receive a 403. The APISIX version in use determines which checks are enforced by default, so the team confirms those defaults against the changelog. Done when the route configuration is committed and the values match the written design record.
Send valid, tampered and wrong-audience test tokens
The test lead sends four requests to the route: a valid token, a token with an altered payload or signature, a token issued for a different audience, and a token from a non-matching issuer. The valid token should reach the upstream, and each invalid token should be rejected with the status the design expects. The tester records the response codes and the upstream logs for each case. Done when all four results match the expected outcomes and the evidence is saved with the change ticket.
Confirm fail-closed behavior when discovery is unreachable
The tester blocks outbound access from the gateway to the identity provider's discovery endpoint in a non-production environment, then sends a valid token through the route. The request must be refused rather than passed through unchecked. The team repeats the test for the introspection endpoint if that path is in use. Done when the route refuses requests during the outage and resumes normal validation once access is restored, and the result is logged.
Record the APISIX version and rerun checks on upgrade
The platform owner records the exact APISIX release, the plugin configuration hash, and the identity provider version in the runbook. Behavior of openid-connect has changed across releases, including default TLS verification and fail-closed rules, so each upgrade triggers a rerun of the test set above. Done when the runbook lists the version and the test evidence, and an owner is named for repeating the checks after each change.
Security and operational risks of each validation path
Both validation paths fail in different ways, and the failures are quiet until a provider outage, a rotated key or a misconfigured issuer reaches production. The cards below cover the controls that decide whether a token check fails closed, stays current with key rotation and keeps secrets and token values out of logs.
Fail-closed behavior on discovery failure
Introspection and JWKS paths both depend on the provider's discovery document to find endpoints and keys. The openid-connect plugin in APISIX 3.18.0 made bearer introspection fail closed when that document is unavailable, so requests are rejected instead of passed through. Confirm the APISIX version in your image, then test by blocking the provider's discovery URL in staging and checking that protected routes return an error rather than an upstream response.
Key rotation and JWKS cache handling
With local signature checks, the gateway holds a copy of the provider's signing keys, so a rotation can cause valid tokens to fail or, if the cache is never refreshed, a revoked key to keep verifying. Ask how the plugin refreshes keys when a token carries an unknown key ID, how long cached keys live, and who notifies your team when the provider rotates. Rehearse a rotation in staging before the production date.
Client secret storage
The openid-connect plugin needs a client ID and client secret for introspection and for the code flow, and those values are stored in the APISIX configuration. Anyone who can read the Admin API or the etcd data can often read them. Store the secret in a managed secrets store and reference it from configuration, restrict Admin API access, and plan a rotation procedure that updates the provider and the gateway together.
TLS verification of provider calls
Introspection and discovery calls travel from the gateway to the identity provider, and their security depends on certificate verification. APISIX 3.16.0 changed the default of ssl_verify from false to true, but older configurations or copied examples may still disable it. Check the effective value on every route, confirm the provider's certificate chain is trusted by the gateway, and treat any disabled verification as a finding to fix before go-live.
Clock skew on exp and nbf
Local verification compares the token's exp and nbf claims with the gateway's clock, so drift between nodes can reject valid tokens or accept expired ones at the edge. Introspection moves the expiry decision to the provider, which shifts the risk to network latency and provider availability. Confirm time sync on every gateway node, decide how much leeway is acceptable, and test a token that expires during a long-running client session.
Logging rejected tokens without leaking them
Rejected requests are useful for investigation, but raw bearer tokens, client secrets and introspection responses in logs become credentials for anyone with log access. Set the access log format to record the request path, consumer or subject identifier, status code and rejection reason, and leave out the Authorization header. Check the error log level in production and confirm that your log platform applies the same retention and access rules as other sensitive data.
Questions teams ask before choosing introspection or JWKS
Which path is faster, introspection or local JWKS verification?
Local verification is usually faster per request, because APISIX checks the token signature with a key it already holds and does not call the identity provider on each request. Introspection adds a network round trip to the provider's introspection endpoint, so the added latency depends on where the provider sits relative to your gateway and how it performs under load. The openid-connect plugin validates through introspection by default, and setting public_key or use_jwks switches to local signature checks that skip introspection. Measure both paths in your own network before deciding, since the difference is driven by topology rather than by the plugin alone.
How does token revocation work with each option?
Introspection asks the identity provider whether a token is still active, so a revoked token is rejected on the next call that reaches the provider. Local JWKS verification only checks the signature, expiry and claims, so a token stays valid at the gateway until it expires, unless you add a separate revocation check. Choose a short token lifetime if you rely on local verification, and confirm with your identity provider how revocation is exposed. Keycloak, for example, documents its own token and session settings, which your team should review alongside the gateway configuration.
What happens if the identity provider is unavailable?
With introspection, an unreachable provider means APISIX cannot confirm token status, so the request depends on how the plugin is configured. APISIX 3.18.0 made bearer introspection fail closed when the discovery document is unavailable, which means requests are denied rather than passed through. With local JWKS verification, the gateway keeps validating tokens while the provider is down, as long as it has a current key set cached, which shifts the risk to key rotation and revocation timing. Test both failure modes in a non-production environment and document which behavior your risk owners accept.
How much effort does the setup take, and what drives it?
Effort is driven by how many identity providers and clients you connect, how many routes need different scopes or audiences, and how much of the validation logic you own. Introspection is typically simpler to start because the provider does the token checking, while local verification requires key discovery, rotation handling and careful configuration of issuer and audience checks. Requirements that add work include multiple tenants, service-to-service tokens, and mapping claims to consumers or headers. Ask any partner to break the estimate down by route groups, identity providers and test cases, and to name what is excluded.
Can an internal team set this up without outside help?
Often yes, if the team already runs APISIX and the identity provider and has someone who understands OAuth 2.0 token formats, scopes and audiences. The hard parts are usually not the plugin settings but the agreements about issuer values, audience names, token lifetimes and failure behavior between the gateway team and the identity team. Teams new to either system tend to benefit from a short review of the design and a test plan before go-live. Check the APISIX changelog for the behavior in your release, since defaults and checks changed across recent versions.
What should we ask a partner for in a fixed-scope quote?
Ask for a written scope that names the identity providers, the APISIX version and deployment mode, the routes and scopes covered, and the validation method chosen for each group. The quote should list deliverables such as configuration as code, test cases for expired, wrong-issuer, wrong-audience and missing-scope tokens, a failure-mode test, and documentation for operations. Ask which items are one-time work and which recur, such as upgrades or retainer support, and what is excluded, such as changes to the identity provider itself. DeployOpen agrees scope, deliverables and timelines in writing before work starts, and does not publish a price list.
How do upgrades change the behavior of these checks?
Upgrades can change defaults and enforcement, so the same configuration may behave differently after a version change. The APISIX changelog records that ssl_verify defaulted to true starting in 3.16.0, that required_scopes returns 403 when scopes are missing, and that 3.18.0 and 3.19.0 added stricter issuer, audience and discovery checks. Review the changelog for every version between your current release and the target before upgrading, and rerun your token test suite in staging. Pin the version you deploy and plan upgrades as a scheduled activity.
How DeployOpen scopes and delivers OIDC validation on APISIX
DeployOpen plans, implements and documents self-hosted APISIX gateways inside your own cloud accounts, data centers or restricted networks. For token validation, we start from your identity provider, your token format and your failure requirements, then build the openid-connect configuration and its tests around the validation method your team can operate.
How we scope
- Written scope lists each protected route, the identity provider, and whether validation uses introspection, JWKS or a public key.
- We record token lifetimes, revocation needs, expected issuer and audience values, and required scopes before any configuration starts.
- Engagements are fixed-scope, with deliverables and timelines agreed in writing before work begins.
How we build
- We configure the openid-connect plugin on APISIX with discovery, issuer, audience and required scope checks set explicitly.
- We set fail-closed behavior for unavailable discovery documents and test the gateway's response to expired, revoked and wrong-audience tokens.
- We run latency and failure tests against your identity provider and confirm the gateway denies requests when validation cannot complete.
How we hand over
- You receive the route and plugin configuration, key and discovery settings, and a record of each validation decision with its reason.
- Runbooks cover key rotation, JWKS refresh behavior, identity provider outages and how to roll back to a previous configuration.
- Test cases for accepted and rejected tokens are delivered so your team can rerun them after each change.
How we support
- Ongoing support, upgrades and continuous testing are available as retainers, including review when APISIX releases change plugin behavior.
- We can rerun validation tests after identity provider upgrades or changes to signing keys, issuers or scopes.
- Ask any quote to name who maintains the identity provider settings, who owns gateway upgrades and who approves changes to validation rules.

