Skip to main content

JWT Authentication

AISIX can authenticate agents with short-lived credentials in JSON Web Token (JWT) format from an OpenID Connect (OIDC) identity provider instead of long-lived caller API keys. Each verified external identity maps to a caller API key and inherits its model access, rate limits, and usage attribution. In AISIX Cloud, the mapped key also carries its budget.

Supported providers include Keycloak, Entra ID, Okta, Auth0, and any OIDC-compliant provider that signs JWT tokens with a supported algorithm. AISIX verifies the token's signature and claims on every request. The agent does not need the caller API key's plaintext value.

Dashboard single sign-on for human operators and gateway JWT authentication for agent requests are independent. Configuring one does not affect the other.

How It Works

When an environment has at least one enabled OIDC provider, AISIX inspects each request's bearer token:

  1. If the bearer is a JWT, its iss (issuer) claim selects the matching trust provider. A token whose issuer matches no enabled provider is rejected.
  2. AISIX verifies the token's signature against the provider's JSON Web Key Set (JWKS), and validates the registered claims: exp (expiration, always required), aud (audience, matched against the provider's accepted audiences), and nbf (not-before) when present.
  3. The provider's required_scopes and bound_claims requirements are enforced.
  4. The value of the provider's identity claim (sub by default) selects the caller API key whose jwt_subject equals it and whose jwt_provider names this provider. The request then runs as that key. Scoping the binding to the provider means a second trusted provider cannot mint a token that impersonates this provider's identity.
  5. When no key binds the identity directly, the provider's claim mappings — priority-ordered rules matching the verified claims — can resolve the request to an existing key, so whole groups of identities share one governed key without per-identity registration. A token matching neither a binding nor a mapping is rejected.

AISIX rejects tokens that fail verification or do not map to a caller API key before the request reaches a provider, MCP server, or vector store. Signing-key rotation at the identity provider is picked up automatically, with no gateway restart.

Prerequisites

Before starting, prepare the following:

  • One of these configuration paths:
    • AISIX Cloud with an environment and an admin token that has the write scope. For On-Premises, follow the AISIX Cloud Quickstart. To request Hybrid Cloud access, contact API7.
    • An open-source AISIX gateway that loads a declarative resources.yaml file.
  • An OIDC identity provider that issues JWT tokens to your agents, and its issuer URL. You also need either its JWKS endpoint URL or its OIDC discovery document (<issuer>/.well-known/openid-configuration).
  • A model alias the caller should be allowed to use and, for the AISIX Cloud workflow, its model ID. If you have not created one yet, configure Provider Keys and Model Aliases first.
  • curl and jq. The open-source AISIX gateway also requires OpenSSL for the credential-generation command shown below.

The provider must sign tokens with an asymmetric algorithm supported by AISIX: RSA (RS256, RS384, RS512, PS256, PS384, or PS512), ECDSA (ES256 or ES384), or EdDSA. HMAC-signed JWT tokens are rejected.

The following sections first show the AISIX Cloud Admin API workflow. For the open-source AISIX gateway, see Open-Source AISIX Gateway Configuration.

Export the base URL, the admin token, the environment ID, and the model ID:

export AISIX_CP="http://localhost:8080/api"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"
export MODEL_ID="YOUR_MODEL_ID"

Register a Trust Provider

Register the identity provider AISIX should trust. At minimum, provide the issuer and the accepted audiences:

curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/oidc_providers" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "corp-keycloak",
"issuer": "https://sso.example.com/realms/agents",
"audiences": ["aisix-gateway"],
"required_scopes": ["ai.access"],
"bound_claims": {
"department": "ai-lab"
}
}' | jq

The response returns the created provider, including the defaults AISIX filled in:

{
"oidc_provider": {
"id": "b2c3d4e5-6789-4abc-def0-123456789abc",
"env_id": "9be9891a-6a53-4bd8-a897-a03fe38a1ca5",
"name": "corp-keycloak",
"issuer": "https://sso.example.com/realms/agents",
"audiences": ["aisix-gateway"],
"identity_claim": "sub",
"required_scopes": ["ai.access"],
"bound_claims": {
"department": "ai-lab"
},
"leeway_secs": 0,
"enabled": true,
"created_at": "2026-07-27T12:00:00Z",
"updated_at": "2026-07-27T12:00:00Z"
}
}

Provider Fields

FieldDescription
issuerExpected iss claim, compared exactly against the token. Unique within the environment.
audiencesAccepted aud values. A token's audience must contain at least one of these. Tokens with no audience claim are rejected.
jwks_uriEndpoint the signing keys are fetched from. Omit it to resolve the endpoint from the issuer's OIDC discovery document.
identity_claimClaim whose value selects the caller API key, matched against each key's jwt_subject. Dots traverse nested objects, for example resource_access.account. Defaults to sub.
required_scopesScopes that must all be present in the token's scope claim (a space-delimited string or an array).
bound_claimsAdditional claim requirements. Each key names a claim, with dots traversing nested objects. A string claim must equal one of the expected values; an array claim must contain one of them.
leeway_secsClock-skew allowance from 0 to 300 seconds for the time-based claims. Defaults to 0.
enabledWhether the provider participates in authentication. Defaults to true.

If you omit jwks_uri, AISIX resolves and caches the signing-key endpoint from the issuer's discovery document. Provide jwks_uri explicitly when the discovery document is not reachable from the gateway.

Bind a Caller API Key to an Identity

Create (or update) a caller API key with two fields set together:

  • jwt_subject: the external identity a verified token maps to. Set it to the value your identity provider puts in the claim named by the provider's identity_claim.
  • jwt_provider: the name of the OIDC provider allowed to assert that subject. Only a token issued by this provider is ever mapped to the key.
curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"display_name": "billing-agent",
"allowed_models": ["'"$MODEL_ID"'"],
"jwt_subject": "agent-billing-01",
"jwt_provider": "corp-keycloak"
}' | jq

The jwt_provider and jwt_subject pair is unique within the environment, and both must be set together. Give each agent identity its own caller API key so model access, rate limits, and usage attribution apply independently. In AISIX Cloud, each identity also inherits the key's budget. Agents authenticate with their JWT, so you do not need to distribute the key's plaintext value.

Open-Source AISIX Gateway Configuration

For the open-source AISIX gateway, declare the OIDC provider and JWT-bound caller API key in resources.yaml. The model alias in allowed_models must also be defined in the file:

resources.yaml
_format_version: "1"

provider_keys:
- display_name: openai-prod
provider: openai
adapter: openai
api_key: ${OPENAI_API_KEY}
api_base: https://api.openai.com/v1

models:
- display_name: gpt-4o-prod
provider: openai
model_name: gpt-4o
provider_key: openai-prod

oidc_providers:
- name: corp-keycloak
issuer: https://sso.example.com/realms/agents
audiences: ["aisix-gateway"]
required_scopes: ["ai.access"]
bound_claims:
department: ai-lab

api_keys:
- display_name: billing-agent
key_env: BILLING_AGENT_KEY
allowed_models: ["gpt-4o-prod"]
jwt_subject: agent-billing-01
jwt_provider: corp-keycloak

api_key supplies the model provider credential from OPENAI_API_KEY.

key_env names the environment variable containing the caller API key's plaintext value.

AISIX requires the caller credential when loading any caller API key, even when the agent authenticates only with JWT tokens. Set both variables for the gateway process, and do not distribute BILLING_AGENT_KEY to the agent:

export OPENAI_API_KEY="YOUR_PROVIDER_API_KEY"
export BILLING_AGENT_KEY="$(openssl rand -hex 32)"

Validate and load the file as described in the Resources File Reference. After it loads, use the same JWT request shown in the next section.

Authenticate a Request

Have the agent obtain a token from your identity provider. Set the model alias and token, then send the token on the proxy API exactly like a caller API key:

export MODEL_ALIAS="YOUR_MODEL_ALIAS"
export AGENT_JWT="eyJhbGciOiJSUzI1NiIsImtpZCI6..."

curl -sS -X POST "http://127.0.0.1:3000/v1/chat/completions" \
-H "Authorization: Bearer $AGENT_JWT" \
-H "Content-Type: application/json" \
-d '{
"model": "'"$MODEL_ALIAS"'",
"messages": [{"role": "user", "content": "Hello"}]
}' | jq

AISIX verifies the token and maps it to the billing-agent key: its sub claim agent-billing-01 matches the key's jwt_subject, and the token's issuer resolves to the corp-keycloak provider named in the key's jwt_provider. The request then runs under that key's permissions. The token's aud must include aisix-gateway. It must also carry the ai.access scope and the department: ai-lab claim required by the provider.

Rejection Reasons

On OpenAI-style proxy routes, a rejected token carries a stable error.code so clients can react without parsing messages. Anthropic-style routes omit code and use the HTTP status and Anthropic-compatible error.type; see Headers and Error Codes.

OpenAI-style error.codeHTTP statusMeaning
jwt_expired401The token's exp deadline has passed. Fetch a fresh token.
jwt_invalid401The token is malformed or fails issuer, signature, signing algorithm, audience, required-claim, or not-before validation.
jwt_claims_rejected403The token is valid but does not satisfy the provider's required_scopes or bound_claims.
jwt_identity_unmapped401The configured identity claim is missing or is not a string, or the identity resolves to no key — no caller API key has matching jwt_provider and jwt_subject values and no claim mapping matched. Check the token claim, key binding, and mappings.
jwks_unavailable503AISIX could not resolve or fetch the provider's signing keys. Check the OIDC discovery or JWKS endpoint, then retry.

Key Rotation

When your identity provider introduces a signing key, AISIX refreshes the cached key set after it sees an unrecognized key ID. The refresh is rate-limited to once per second, so a request received immediately after another refresh may need to be retried. No configuration change or gateway restart is needed.

AISIX treats a cached JWKS as fresh for 10 minutes. After that interval, the next authentication request triggers a refresh. Once the refreshed set no longer contains a retired key, tokens signed by that key stop authenticating. If the JWKS endpoint is unavailable during the refresh, AISIX keeps the last successfully fetched key set. Existing authentication can continue, but the retired key remains trusted until a later refresh succeeds.

Update or Remove a Trust Provider

AISIX Cloud

Use the Admin API to update an existing provider. For example, disable it to stop trusting its tokens while keeping its configuration:

export OIDC_PROVIDER_ID="b2c3d4e5-6789-4abc-def0-123456789abc"

curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/oidc_providers/$OIDC_PROVIDER_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": false}' | jq

Set enabled to true to trust the provider again. You can also update its issuer, accepted audiences, JWKS endpoint, identity claim, required scopes, bound claims, or clock-skew allowance with the same PATCH operation. The provider name cannot be changed after creation.

Delete the provider to remove the trust entirely:

curl -sS -X DELETE "$AISIX_CP/environments/$ENV_ID/oidc_providers/$OIDC_PROVIDER_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" | jq

Deleting a provider does not affect the caller API keys or their jwt_subject bindings. Those keys still authenticate with their plaintext values, and can be re-associated with a new provider later.

Open-Source AISIX Gateway

Edit the provider under oidc_providers in resources.yaml. Set enabled: false to disable it while retaining its configuration, change its fields to update the trust policy, or remove the entry to delete the provider.

The caller API key remains in api_keys when you disable or remove its provider. Its plaintext value continues to authenticate. To remove the JWT identity mapping as well, delete both jwt_subject and jwt_provider from the key.

After each change, validate and reload the file. Follow Reload a Resources File for the complete workflow.

Next Steps

  • JWT Claim Mappings: admit whole classes of identities — departments, groups, applications — through priority-ordered claim rules instead of per-identity bindings.
  • Keycloak Integration: a verified end-to-end walkthrough from a Keycloak realm to mapped, attributed requests.
  • Caller API Keys: manage the model access and other controls inherited by each mapped identity.
  • API Key and Model Rate Limits: limit the request volume or token usage of JWT-authenticated callers.
  • Configuration Propagation: understand how configuration changes reach AISIX gateways.