Skip to main content

JWT Claim Mappings

JWT Authentication can bind one external identity to one caller API key through its jwt_provider and jwt_subject fields. That works for a fixed fleet of agents. It does not scale to an enterprise identity provider asserting departments, groups, or applications for hundreds of people. Registering a key per person duplicates the IdP's directory, and changes there never propagate.

Claim mappings close that gap. A mapping matches verified JWT claims, such as a department name or group membership, and resolves the request to an existing caller API key. Everyone the rule admits inherits that key's model access, tool access, and rate limits. In AISIX Cloud, its budget also applies. Usage events remain attributed to the individual identity from the token.

Claims only select a key that an operator already created. No claim value becomes configuration: a token cannot name an upstream, widen a model allowlist, or create a budget. AISIX rejects a token that matches no direct binding or claim mapping.

How Mappings Are Evaluated

For each request with a JWT bearer, after the full trust-provider verification described in JWT Authentication:

  1. If a caller API key binds the token's subject directly through jwt_subject and jwt_provider, the request runs as that key. The direct binding is authoritative for its subject, including when the key is disabled and the request is rejected. Mappings never override it.
  2. Otherwise, AISIX evaluates the enabled mappings whose jwt_provider names the matched trust provider. Lower priority values run first, with ties broken by name. The first mapping whose match conditions all hold selects the key.
  3. If no mapping matches, the request is rejected with jwt_identity_unmapped. There is no default admission.

The match field of a mapping is a list of conditions, which must all hold:

FieldDescription
claimNon-empty claim path. Dots traverse nested objects (for example realm_access.roles). A missing claim never matches.
opWith exact, the claim must be a string equal to one of values. With contains, the claim must be an array containing one of values among its string items; non-string items are ignored. A claim whose type does not fit the operator never matches.
valuesOne or more accepted strings. The condition holds when any one matches.

The trust provider named by jwt_provider must verify the token before AISIX considers any mapping. In AISIX Cloud, the mapped key must continue to exist in the same environment, so deleting a key that a mapping resolves to is refused — repoint or delete the mapping first. In a declarative resources file, an unknown provider or key reference prevents the configuration from loading.

Prerequisites

Before starting, prepare the following:

  • A registered OIDC trust provider and model configured as described in JWT Authentication.
  • A caller API key to act as the shared policy key. Configure the model access, tool access, and rate limits that admitted identities should inherit. In AISIX Cloud, matching budgets also apply.
  • One configuration path:
    • AISIX Cloud with an environment, an attached gateway, and an admin token with write scope. Record the policy key's ID.
    • An open-source AISIX gateway with a complete resources.yaml file and access to the gateway process environment.
  • curl and jq for the AISIX Cloud workflow. The open-source path uses OpenSSL to generate the policy-key value shown below.

Review Trust Provider Requirements

AISIX evaluates trust-provider requirements before claim mappings. Remove or update any bound_claims condition whose decision the mapping should make. For this workflow, remove the JWT Authentication example's department: ai-lab condition because the mapping decides which departments to admit.

Keep required_scopes requirements that admitted identities satisfy. The examples retain ai.access, so mapped tokens must carry that scope. Apply any provider changes as described in Update or Remove a Trust Provider.

Configure Claim Mappings

Configure claim mappings using the management path for your deployment.

AISIX Cloud

Export the AISIX Cloud Admin API connection details, environment ID, and policy-key ID:

# AISIX_CP includes /api and has no trailing slash.
# The local On-Premises quickstart uses http://localhost:8080/api.
export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_URL"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"
export POLICY_KEY_ID="YOUR_API_KEY_ID"

Admit everyone whose department claim equals finance under the policy key:

curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/claim_mappings" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "finance-dept",
"jwt_provider": "corp-keycloak",
"priority": 100,
"match": [
{
"claim": "department",
"op": "exact",
"values": ["finance"]
}
],
"resolve": {
"api_key_id": "'"$POLICY_KEY_ID"'"
}
}' | jq

The response echoes the created mapping. When some gateways in the environment run a release that predates claim mappings, it also carries a warnings array. Those gateways skip the rule entirely and keep rejecting the identities it should admit, so upgrade them before relying on it.

Mapping Fields

FieldDescription
nameMapping name, unique within the environment and fixed at creation. Also the evaluation tie-break for equal priorities.
jwt_providerName of the OIDC provider whose tokens this mapping applies to. A mapping never matches a token verified by a different provider, so two providers cannot select each other's keys.
priorityNon-negative evaluation order among the provider's mappings. Lower values are evaluated first. Defaults to 0.
matchFrom 1 to 16 claim conditions, which must all hold (see the table above).
resolve.api_key_idID of the caller API key matching requests run as.
enabledWhether the mapping participates in evaluation. Defaults to true; a disabled mapping is kept but skipped.

The AISIX Cloud Admin API accepts mapping names and provider names up to 120 characters. A mapping contains from 1 to 16 conditions. Each condition has a claim path up to 256 characters and from 1 to 64 accepted values, each up to 256 characters.

Update a mapping with PATCH .../claim_mappings/{claim_mapping_id}. The name is fixed, so delete and recreate the mapping to rename it. Remove a mapping with DELETE. Changes take effect on new requests without a gateway restart. Identities admitted only by a deleted or disabled mapping stop authenticating as soon as the gateway picks up the change.

In the Dashboard, the environment's Claim mappings page manages the same rules and lists them in evaluation order.

Open-Source AISIX Gateway

This configuration extends the complete resources file from JWT Authentication. Keep its _format_version, provider-key, and model entries. Set the new policy-key value in the gateway process environment:

export FINANCE_POLICY_KEY="$(openssl rand -hex 32)"

Replace corp-keycloak with this entry; do not add another provider with the same name. It keeps the ai.access scope while moving the department decision to the mapping:

resources.yaml (OIDC provider)
oidc_providers:
- name: corp-keycloak
issuer: https://sso.example.com/realms/agents
audiences: ["aisix-gateway"]
required_scopes: ["ai.access"]

Add finance-policy-key to the existing api_keys list. Add finance-dept to claim_mappings, creating the top-level claim_mappings collection once if it is absent. Preserve existing entries in both collections, and do not create a second copy of either top-level collection key.

In the assembled resources.yaml, resolve.api_key references the policy key by its display_name:

resources.yaml (API key and claim mapping)
api_keys:
- display_name: finance-policy-key
key_env: FINANCE_POLICY_KEY
allowed_models: ["gpt-4o-prod"]

claim_mappings:
- name: finance-dept
jwt_provider: corp-keycloak
priority: 100
match:
- claim: department
op: exact
values: ["finance"]
resolve:
api_key: finance-policy-key

The name, jwt_provider, priority, match, and enabled fields have the same evaluation behavior as their AISIX Cloud counterparts. The open-source schema validates non-empty names, providers, condition lists, claim paths, and value lists. It does not apply the AISIX Cloud Admin API's maximum lengths or list sizes.

The file loader resolves the reference at load time and rejects unknown provider or key names, an empty condition list, or a mapping whose jwt_provider names no provider in the file. A typo fails the load instead of silently never matching.

Validate and apply the complete file by following Reload a Resources File. If FINANCE_POLICY_KEY is new, use Add New Environment Variables to recreate the gateway with it.

Exporting the variable on the host and sending SIGHUP cannot add it to an already-running container.

To disable the mapping without removing its configuration, set enabled: false and reload the file. To remove the mapping, delete its entry and reload. Before deleting a policy key, remove or repoint every mapping that references it. You can apply those changes in an earlier reload or in the same resources file update. The file loader rejects any configuration in which a mapping references a missing key.

Layer Mappings with Priorities

Rules compose by priority. Give a narrower rule a lower value so it wins for the identities it describes, and let a broader rule catch the rest.

For AISIX Cloud, export the ID of a second policy key, then create the narrower mapping:

export ADMIN_KEY_ID="YOUR_ADMIN_API_KEY_ID"

curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/claim_mappings" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "platform-admins",
"jwt_provider": "corp-keycloak",
"priority": 50,
"match": [
{
"claim": "groups",
"op": "contains",
"values": ["platform-admin"]
}
],
"resolve": {
"api_key_id": "'"$ADMIN_KEY_ID"'"
}
}' | jq

A token carrying both department: finance and the platform-admin group now resolves through platform-admins at priority 50 rather than finance-dept at priority 100. Identities that need different effective access controls should resolve to different policy keys. Multiple mappings can resolve to the same key when they should grant the same access.

For the open-source gateway, Keycloak Integration shows the complete two-rule resources file for the same priority relationship.

Verify Claim Mapping

Obtain a JWT whose verified claims should match the mapping and whose subject has no direct jwt_subject and jwt_provider binding. Then request a model that only the expected policy key allows, or confirm that the expected jwt_claim_mapping appears in AISIX Cloud logs or a configured exporter. This distinguishes a mapping match from access through another key.

Also test the default-deny and priority paths that apply to your rules:

  • Send a valid JWT that matches no direct binding or mapping. On an OpenAI-style proxy route, the gateway should return 401 with error.code: jwt_identity_unmapped.
  • If mappings overlap, use a subject with no direct binding and send a JWT that matches both. Request a model allowed only by the policy key selected by the higher-priority mapping, or confirm the expected jwt_claim_mapping attribution. This verifies that the lower priority value won.

For a reproducible Keycloak setup and verification matrix covering both configuration paths, see Keycloak Integration.

Per-Identity Usage Attribution

Usage events for requests admitted through a mapping include three attribution fields. Configured observability exporters receive the same fields:

FieldDescription
jwt_subjectThe token's identity-claim value, identifying who ran the request even when many identities share the policy key.
jwt_providerThe trust provider that verified the token.
jwt_claim_mappingThe mapping that admitted the request. Empty for identities bound directly through jwt_subject and jwt_provider.

In AISIX Cloud, the fields are also visible in the environment's Logs and included in CSV exports. The Logs page filters by JWT subject, while the jwt_subject and jwt_claim_mapping query parameters on the usage-events API narrow programmatic reads.

The subject is personal data when the identity claim contains names or email addresses. Review where exporters deliver usage data before enabling them alongside claim mappings.

Rejection Behavior

Mapped authentication extends the JWT rejection table. AISIX rejects a verified token before it reaches a provider, MCP server, or vector store when the identity cannot resolve safely.

Each failure below returns HTTP 401. OpenAI-style routes return jwt_identity_unmapped as error.code, while the reason label on aisix_auth_decisions_total identifies the operator-side cause:

reasonMeaning
jwt_identity_unmappedThe verified identity has no direct key binding, and no enabled mapping for its trust provider matches all claim conditions.
claim_mapping_target_missingA mapping matched, but its target caller API key is missing from the active gateway configuration. AISIX Cloud and resources-file validation ordinarily prevent this state. If it occurs, check configuration propagation and the gateway's active resources.
jwt_binding_ambiguousMore than one caller API key has the same jwt_provider and jwt_subject binding, so the gateway fails closed instead of evaluating mappings. Normal configuration validation prevents this state.

Next Steps