Apache APISIX API authentication with Okta: what the integration does
If your APIs sit behind APISIX and Okta is your identity provider, the openid-connect plugin is the supported way to have the gateway validate who is calling. The plugin works with Okta among other providers such as Keycloak, Auth0, Microsoft Entra ID and Google, and it covers the authorization code, client credentials, token introspection and PKCE flows. Two validation paths matter most. By default, APISIX validates each bearer token by calling the provider's introspection endpoint. If you set public_key or use_jwks, APISIX verifies the JWT signature locally and skips introspection, which removes a network call per request but changes what the gateway can see about revoked or inactive tokens.
The choice between these paths is an architecture decision, not only a performance tweak. Introspection keeps the gateway dependent on Okta's endpoint on every request, so you need to size that dependency, decide how the gateway behaves if Okta is unreachable, and confirm how token revocation reaches your APIs. Local verification depends on keys published by the authorization server and on the claims your tokens carry. Before choosing, confirm with your Okta administrator which authorization server, issuer and audience your APIs will use, and whether the tokens are access tokens intended for your APIs rather than ID tokens meant for a browser client.
The same plugin also covers browser login for internal applications, where APISIX runs the authorization code flow with PKCE and manages the session, so users sign in through Okta before reaching the upstream. Service-to-service calls usually use the client credentials flow instead. Treat these as separate client types in Okta, each with its own application registration and scopes. Plan the app registrations, redirect URIs and secret storage before configuration starts, because they decide which calls the gateway can authenticate and how much of the trust decision stays in Okta.
What you need before configuring Okta and APISIX
Before any route is protected, the APISIX version, the Okta side and the network path between them need to be settled. Each card below covers one of these prerequisites, and together they determine whether token validation works on the first attempt. Confirm every endpoint and plugin field against the openid-connect plugin documentation for your exact APISIX version.
Target APISIX version
Pin the APISIX version before writing any configuration, because plugin defaults change between releases. The current release in our reference set is 3.19.0, and the downloads page does not mark any release as long-term support, so confirm your support window with your organization's lifecycle policy. Record the exact version in your change records so that later upgrades can be checked against the version-specific notes in the openid-connect plugin documentation and the project CHANGELOG.
Okta org and authorization server
Decide which Okta authorization server issues tokens for the APIs, and confirm its issuer URL, JWKS location and introspection availability in your org. A custom authorization server gives you control over scopes and audience values, which the gateway checks. Ask your Okta administrator who owns the authorization server, who can change its claims and scopes, and whether separate servers exist for development and production.
OIDC application registration
Create one Okta application for each role the gateway plays: a web application for browser login to internal apps, and a service application if clients use client credentials. Record the client ID, the client secret storage location and the allowed redirect URIs for each. Keep the secret out of route configuration and plan how it is referenced at runtime, since the plugin takes the client secret as a field value.
Network path to Okta endpoints
APISIX must reach the Okta discovery document, token endpoint, JWKS endpoint and, if used, the introspection endpoint over HTTPS. Confirm egress rules from each gateway node or pod, any proxy the platform requires, and DNS resolution for the Okta domain. In restricted or air-gapped networks, agree in advance which endpoints are reachable, because a blocked introspection call shows up as request failures rather than a clear configuration error.
CA trust for TLS
Validate that the gateway trusts the certificate chain presented by Okta and by any internal identity proxy in front of it. The openid-connect plugin's ssl_verify default changed from false to true in APISIX 3.16.0, so builds that relied on the old default will start failing TLS checks after an upgrade. Ask your security team which CA bundle the gateway should use and how that bundle is updated and monitored.
Plugin field verification
Before you write route configuration, open the openid-connect plugin page for your target version and confirm the exact field names, required scopes behavior and claim validator syntax. Field names, defaults and accepted discovery settings are version-specific, so do not copy examples from older articles. Ask your implementation team to document which fields were checked against which version, and to keep that record with the route configuration.
How to configure the openid-connect plugin for Okta
This sequence takes an Okta authorization server, its clients and claims, and wires them into an APISIX route so that API calls are authenticated, scope-checked and audience-checked before they reach an upstream. Each step ends with a check you can run to confirm the gateway behaves as intended.
Create the Okta authorization server and scopes
In Okta, create or choose a custom authorization server for the API, then define the scopes that the API will require, such as a read scope and a write scope named for the operations they permit. Record the issuer URI of the authorization server, because the discovery URL and the issuer check both depend on it. The step is done when the scopes appear on the authorization server and a test token request returns an access token whose scp claim lists them. Confirm the exact Okta console labels and token settings against Okta's current documentation for your tenant.
Register the API and browser clients
Create two applications in Okta: a browser client for the internal app using the authorization code flow with PKCE, and a service client for machine callers if you need client credentials. Set the redirect URI for the browser client to the callback path that APISIX will serve on the route. Note the client ID and secret for each client and store the secret in your secrets system rather than in route configuration. The step is done when each client can obtain a token from the authorization server in a test request.
Define audience and claims
Set the audience of the custom authorization server to the API identifier your APISIX route will protect, and add claims that the gateway will check, such as the issuer and the audience. Decide which claims carry the authorization data your upstream needs, and map them into the token only if they are required. The step is done when a decoded access token shows the expected iss, aud and scp values for the API. Confirm which claims your Okta edition and authorization server configuration can emit before you rely on them.
Add the openid-connect plugin to a route
Create or update the APISIX route that serves the API, and add the openid-connect plugin. Set the discovery URL to the well-known OpenID configuration endpoint of the Okta authorization server, and set the client ID and client secret for the API. Set ssl_verify explicitly so the TLS check does not depend on a version default, and confirm the setting against the plugin reference for the APISIX version you run, since the default changed in 3.16.0. The step is done when the route is saved and APISIX reports the route as active through the Admin API.
Choose introspection or JWKS validation
Decide how APISIX validates bearer tokens. With the default behavior, the plugin calls the provider's introspection endpoint for each request, which keeps revocation checks at the authorization server but adds a network call per request. Setting public_key or use_jwks makes APISIX verify the JWT signature locally and skips introspection, which improves throughput but means revoked tokens remain valid until they expire. Record the decision and the expected token lifetime. The step is done when the chosen option is set on the route and a token that is revoked or altered is rejected as expected under that option.
Add required_scopes and claim_validator
Add required_scopes to the plugin with the scopes the route needs, and add claim_validator to check the issuer and audience against the values you defined in Okta. Required scopes return a 403 when a valid token lacks a listed scope, which separates authentication failures from authorization failures in your logs. The step is done when the route config contains both settings and the values match the authorization server exactly, including the trailing path of the issuer.
Test the route with three requests
Run three checks against the route. A request with no bearer token should return 401. A request with a valid token that lacks a required scope should return 403. A request with a valid token carrying the required scope and audience should return 200 and reach the upstream. Repeat the 200 check with a token from the browser client after the login flow, and confirm the gateway logs show the expected outcome for each case. The sequence is complete when all three results match and the test scripts are stored with the route configuration.
Introspection or local JWKS validation: which path to choose
The openid-connect plugin in Apache APISIX offers two ways to validate a bearer token from Okta, and the choice decides how often your gateway talks to Okta and how quickly a revoked token stops working. By default the plugin calls the provider's introspection endpoint, so Okta answers for each token that arrives. Setting public_key or use_jwks changes that: APISIX verifies the JWT signature locally against a key it holds and skips introspection. Local verification removes a network call from every request, but it also removes Okta's live answer about whether the token is still active.
Local verification trades that live check for speed and independence from Okta's availability at request time. The gateway keeps working for tokens it already accepts even if the introspection endpoint is slow or unreachable, which matters for high-volume APIs and for estates where a provider outage should not stop traffic. The cost is that signature checks alone do not reveal a token revoked or disabled after issuance, so access stays open until the token expires. Key rotation adds a second concern: with use_jwks the plugin fetches keys from the issuer's JWKS, while a fixed public_key must be updated by hand when Okta rotates signing keys. Confirm how your Okta org rotates keys and how APISIX refreshes them before you rely on either option.
Decide on revocation requirements first, then latency and dependency. If you need near-immediate revocation for sensitive APIs, keep introspection or shorten token lifetimes in Okta, and test the behavior yourself: revoke a token, send it through APISIX, and record whether the request is rejected and how long that takes. Run the same test with the JWKS path and during a simulated Okta outage. Confirm the revocation semantics, caching behavior and key refresh timing against your own Okta tenant and APISIX version rather than assuming them from the documentation.
Mapping Okta claims, scopes and audiences to APISIX checks
This table maps each Okta token element to the APISIX openid-connect check that enforces it and the setting you adjust. Read it as a checklist: confirm each claim name in your own Okta authorization server before you copy the configuration, because custom claims and scope names vary by tenant.
| Okta element | APISIX check | What to confirm in your Okta setup |
|---|---|---|
| Issuer (iss) | claim_validator checks the issuer value against the Okta authorization server URL | Use the exact issuer of the authorization server that issues your API tokens, not the org URL, and confirm it matches the token you test with |
| Audience (aud) | claim_validator checks the audience against the API identifier you register for the gateway-protected API | Set a distinct audience per API so a token issued for one API cannot call another |
| Scope claim (scp) | required_scopes returns 403 when a listed scope is missing from the token | Confirm whether your authorization server emits scopes in scp or a custom claim, and that the scope names match the ones in required_scopes |
| Custom scope or group claim | Read through claim_validator or a custom check when scopes are not in scp | Ask the Okta administrator which custom claim carries entitlements and whether it is present in access tokens |
| Subject (sub) | Forwarded to upstream as a header or mapped to a consumer for rate limits and logging | Confirm whether sub identifies a user or a service client, since client credentials tokens use the client as subject |
| Client credentials service token | Validated the same way as user tokens, with required_scopes limiting what the service may call | Create a separate Okta app for each service, grant only the scopes that service needs, and avoid sharing one client across services |
| Signing keys (JWKS) | Used when public_key or use_jwks verifies signatures locally, skipping introspection | Confirm the JWKS endpoint of the authorization server and plan key rotation so the gateway picks up new keys |
| TLS to Okta endpoints | ssl_verify defaults to true from APISIX 3.16.0, so Okta certificates must validate | Check the CA trust on gateway nodes before upgrading from an older release that relied on the previous default |
Hardening the Okta integration in APISIX 3.16 to 3.19
The openid-connect plugin ships with settings that decide whether a token is trusted, which routes are protected and how a browser session is established. The cards below cover the defaults and checks that changed or matter most between APISIX 3.16 and 3.19, and the points where an Okta deployment can silently accept traffic it should reject.
Confirm certificate trust to Okta
Since APISIX 3.16.0, the openid-connect plugin's ssl_verify defaults to true. Before upgrading, confirm that the gateway trusts the certificate chain for your Okta org's discovery, token, introspection and JWKS endpoints, including any private or proxy CA in your network. A gateway that cannot verify Okta will fail token checks, so test the path from each gateway node, not only from your workstation.
Enforce required scopes
The required_scopes setting returns 403 when a valid token lacks the listed scopes. Map each route to the Okta scopes that its business function needs, and test a token that is valid but under-scoped to confirm the 403 path. Scope names come from your authorization server configuration, so agree them with the application owners before the route goes live.
Validate issuer and audience
Use claim_validator to check the iss and aud claims so that tokens issued for another Okta app or authorization server are rejected by this API. Confirm the exact issuer string your authorization server publishes, including its path, and the audience value your API expects. Test one token with a wrong audience to verify the rejection.
Store the client secret safely
The client secret for the Okta application is a credential that APISIX needs at runtime. Keep it out of route definitions that are committed to source control, and reference it from a secrets store or environment variable where your deployment mode supports it. Ask who can read the Admin API and etcd, because anyone with those rights can read stored plugin configuration. Plan rotation in Okta and in the gateway together.
Keep PKCE for browser login
For internal browser apps, use the authorization code flow with PKCE rather than a client secret alone in the browser path. Confirm that the Okta application is configured for PKCE and that the plugin settings match, then test a complete login, logout and session expiry. Keep redirect URIs exact, since loose redirect URI lists are a common source of token leakage.
Limit which routes carry the plugin
Attach the openid-connect plugin only to routes that need Okta-protected access, and keep health checks, public documentation and webhook receivers outside it. Review the route list after each change, because a broad plugin on a global or shared service block can block traffic you did not intend to protect. Record the mapping from route to scope in your change record so auditors and engineers can trace it.
Questions teams ask before configuring Okta with APISIX
What drives the cost and effort of protecting APIs with Okta and APISIX?
The main drivers are the number of APIs and routes that need protection, the token validation method you choose, how many browser-based internal applications need a login flow, and how your Okta authorization servers are designed. Each API with its own audience, scope set and consumer type adds configuration and testing work. Browser apps add redirect URIs, session handling and logout behavior to verify. The cost components are the design work, the APISIX configuration, the Okta-side setup and the test plan, and who pays for each depends on whether your team or a partner performs it. One-time work covers design, initial configuration and testing. Recurring work covers rotating client secrets, reviewing scopes as products change and upgrading APISIX. Ask any quote to break these items out by API count and application type so you can see what changes if the scope grows.
How long does an Okta and APISIX authentication project take?
Duration depends on your environment, so no fixed figure applies here, and the most reliable answer comes from a written scope. The schedule is shaped by how many APIs and browser applications are in scope, whether your Okta tenant already has authorization servers, scopes and claims defined, how quickly your network and security teams approve traffic paths between APISIX, Okta and your upstreams, and how much test coverage you require before cutover. Teams that have not yet agreed on token audiences or scope names usually spend the most time before any configuration starts. Ask for a plan that lists each dependency, the owner of each approval and the test stages, so that delays are visible early rather than discovered at go-live.
What do we need to provide before the work starts?
You need three things ready. First, administrative access to the Okta tenant, or a named Okta administrator who can create applications, authorization servers, scopes and claims during the work. Second, network rules that allow APISIX to reach your Okta issuer and, if you use introspection, the introspection endpoint, plus paths from APISIX to each upstream service. Third, a named owner for claims and scopes who decides what each token contains, which audience each API accepts and which scope each route requires. Without that owner, configuration stalls on naming questions. You should also provide the list of APIs and the consumers that call them, along with the environments where testing will take place.
Can our own team configure Okta authentication in APISIX without a partner?
Yes, a capable platform or security team can do it, provided it has the APISIX plugin documentation, a clear test plan and access to a non-production environment. The openid-connect plugin documentation covers the authorization code, client credentials, introspection and PKCE flows, along with the settings for issuer, audience, scope and certificate verification. The harder parts are usually Okta-side design, such as authorization server structure and claim mapping, and writing negative tests that prove an expired token, a wrong audience or a missing scope is rejected. A partner can add value by reviewing that design and building the test suite, but the decision depends on your team's capacity and the number of APIs in scope.
Should we validate Okta tokens with introspection or JWKS?
Choose introspection when you need the provider to confirm each token is still active, and choose local verification when throughput and latency matter more than immediate revocation checks. The openid-connect plugin validates tokens through the provider's introspection endpoint by default. Setting public_key or use_jwks verifies JWT signatures locally and skips introspection, so the gateway no longer calls Okta for every request. Local verification depends on key rotation being handled correctly and on short token lifetimes to limit the effect of a revoked token. Introspection adds a dependency on the Okta endpoint for each request, so plan for its availability and load. Many teams decide per API, using introspection for sensitive operations and local JWKS checks for high-volume read paths.
What changed in APISIX 3.16 that affects Okta token checks?
In APISIX 3.16.0 the openid-connect plugin's ssl_verify default changed from false to true, so the gateway now verifies TLS certificates when calling the identity provider unless you override it. Configurations that relied on the old default may fail after an upgrade if the Okta endpoint certificate chain is not trusted by the gateway. Check the CHANGELOG entry for your target version, test the token flow in staging and confirm that your trust store contains the required authorities. The same review should confirm that required_scopes returns a 403 when a token lacks the needed scopes, and that claim_validator checks issuer and audience, since these determine whether a token issued for another API is rejected.
How do we confirm that required scopes and audiences are enforced?
Test rejection cases as carefully as success cases. Create a token that lacks the required scope and confirm the gateway returns 403. Create a token issued for a different audience and confirm claim_validator rejects it. Create an expired token and a token from a different issuer, and confirm each fails. Run these tests against every route that carries a scope or audience rule, because a missing rule on one route is a common gap. Keep the results as evidence and rerun the suite after each configuration change or APISIX upgrade. A short written matrix that maps each route to its expected audience, scopes and validation method is the most useful artifact for reviewers.
Why Okta token validation fails at APISIX and how to fix it
This table lists the failures teams most often hit when Okta tokens are validated by the APISIX openid-connect plugin, with the likely cause and fix for each. Read it against your logs: match the symptom (TLS error, 401, 403, latency or redirect error) to the row, then confirm the cause in your own Okta and APISIX configuration before changing anything.
| Symptom | Likely cause | Fix to check first |
|---|---|---|
| TLS or certificate errors after upgrading past 3.16.0 | The openid-connect ssl_verify default changed from false to true in APISIX 3.16.0, so the gateway now verifies the Okta or internal CA certificate chain. | Confirm the Okta endpoint certificate chain is trusted by the gateway, add the internal CA to the gateway trust store, and set ssl_verify deliberately rather than disabling it to get past the error. |
| 401 on tokens that look valid | The configured discovery URL or issuer points at a different Okta authorization server (for example, the org server instead of a custom server) than the one that issued the token. | Compare the iss claim in a decoded token with the issuer and discovery URL in the route. Use the authorization server that issued the token and confirm its well-known discovery document loads from the gateway. |
| 401 caused by audience mismatch | The token's aud claim does not match the audience expected by the API, often because the access token was requested with the default audience instead of the API identifier. | Request the token with the API's audience value in Okta, and set the claim_validator audience check to that same value on the route. |
| 403 on requests with a valid token | The required_scopes check returns 403 when the token lacks one or more listed scopes, often because the scope was defined in Okta but not granted to the client or not requested. | Decode the access token and compare its scp claim with required_scopes. Grant the scope to the application in Okta, or remove the scope from the route if it was added in error. |
| 401 after Okta rotates signing keys | Local JWT verification uses cached keys, so tokens signed with a new key fail until the JWKS cache refreshes or the public key is updated. | Use use_jwks with the authorization server's JWKS endpoint so keys refresh automatically, and test a rotation in a non-production environment before relying on it. Avoid pinning a static public_key unless you have a key rotation process for it. |
| Added latency or timeouts on every call | Token introspection makes a network call to Okta for each request, so slow or distant identity endpoints add delay and can time out under load. | Confirm which mode the route uses. Where your security design allows, verify JWT signatures locally with use_jwks, and measure introspection latency from the gateway network before choosing introspection for high-volume routes. |
| Redirect URI mismatch during browser login | The redirect_uri registered in the Okta application does not exactly match the callback URL APISIX sends, including scheme, host, port or path. | Copy the callback URL from the route and register it exactly in the Okta application's sign-in redirect URIs, including the environment-specific host name, then test login in each environment separately. |
| Login loops or session errors behind a load balancer | The public host name or scheme seen by APISIX differs from what the browser uses, so redirects and cookies are generated for the wrong origin. | Confirm forwarded headers and the public URL reach APISIX unchanged, and check that the redirect URI and cookie settings match the external hostname served over HTTPS. |
Testing the Okta policy before routing production traffic
Run the Okta policy checks on a non-production route before any production client reaches the API. The goal is to prove, with recorded results, that the openid-connect plugin accepts what it should and rejects everything else. Create a separate test route with the same plugin settings as the planned production route, pointed at a test upstream that returns a recognizable response. Use the same Okta authorization server, issuer and audience values you intend to use in production, so the test exercises the real policy rather than a stand-in.
Build the test set around the cases that matter for this design. Use a valid access token from a test user and a test client, then an expired token, a token issued for a different audience, a token missing a required scope, and a token from a user or client that you have deactivated or revoked in Okta. For the signing key, rotate the key in Okta and confirm how the gateway behaves in your chosen mode: under introspection the revoked or rotated state should show up on the next call, while under local JWKS verification you should confirm when the gateway refreshes its key set. Expect a 403 for a missing scope and a rejection for a wrong audience, and record the status code and response body for each case. For browser login, run an authorization code flow with PKCE for an internal test app and confirm the session is established and that the redirect URI matches the registered value exactly.
Keep the results as evidence. Store the request sent, the token claims that were tested (with secrets removed), the APISIX version and the plugin configuration as exported from the Admin API, the Okta app and authorization server settings, and the observed status for each case, with the date and the name of the tester. Ask your auditors or security reviewers which of these artifacts they want, and confirm the retention period with your own records policy. Only move the route to production after every case matches its expected result, and keep this test route in place so the same checks can be repeated after upgrades or key changes.
How DeployOpen scopes and delivers the Okta integration
DeployOpen plans, implements, tests, documents and supports self-hosted open-source platforms inside your own infrastructure, and the Okta integration with Apache APISIX follows the same path. We agree the scope in writing before work starts, then build and verify the token checks, route policies and browser login in your environment.
How we scope
- Inventory which routes need bearer tokens, browser login or both, and which consumers call them.
- Decide between introspection and local JWKS verification for each route, based on latency and provider reachability.
- Agree required scopes, expected audience values and issuer settings for each API in a written scope.
How we build
- Configure the openid-connect plugin on test routes with Okta issuer, client and secret references, then check each flow.
- Set required_scopes and claim_validator rules so missing scopes return 403 and wrong issuers or audiences are rejected.
- Review ssl_verify and other settings against the 3.16 to 3.19 changes, and test the configuration on a staging gateway first.
How we hand over
- Deliver the route configuration, plugin settings and test results so your engineers can repeat each check.
- Document the token validation path, the Okta application setup and the owners for each scope and claim.
- Walk your platform and security teams through the runbook for key rotation, failed token checks and upgrades.
How we support
- Offer ongoing support, upgrades and continuous testing as a retainer after handover.
- Re-test authentication rules when APISIX or Okta settings change, and report what changed and what needs review.
- Confirm with your security team and auditors which evidence you need, since DeployOpen prepares evidence but does not issue audit reports.

