Documentsapisix
JWT Authentication
JWT Authentication
Type
Topic
Status
Published
Created
Jul 14, 2026
Updated
Jul 14, 2026

JWT Authentication in APISIX#

The jwt-auth plugin provides token-based authentication at the gateway layer. It sits at priority 2510 in the plugin execution order, running before upstream proxying. When a request arrives, the plugin extracts the JWT from the request, maps it to a Consumer via a claim lookup, verifies the signature against that Consumer's stored key material, and either passes or rejects the request — all without any upstream session state.

Primary source files:

Consumer Model and Credential Storage#

JWT credentials live on Consumers, not on routes. A route only needs "jwt-auth": {} — all key material is stored in the Consumer's credential object .

Each credential must include a unique key field. The plugin extracts this value from the JWT payload claim named key (configurable via key_claim_name) and looks up the matching Consumer . On success, APISIX injects X-Consumer-Username, X-Credential-Identifier, and optional custom label headers upstream .

Supported Algorithms#

The algorithm field on the Consumer credential controls verification mode :

AlgorithmKey fields requiredNotes
HS256 (default)secretShared HMAC key; auto-generated if omitted
HS512secretShared HMAC key
RS256public_keyRSA asymmetric; secret must not be set
ES256public_keyECDSA asymmetric; secret must not be set

Schema enforcement: when RS256 or ES256 is selected, public_key becomes required and no secret is accepted . For symmetric algorithms, if secret is omitted, one is auto-generated .

Asymmetric Algorithms (RS256 / ES256) and External Identity Providers#

With asymmetric algorithms, APISIX only stores the public key on the Consumer — the private key never leaves the identity provider. This makes jwt-auth suitable for verifying tokens issued by external systems (e.g., Keycloak) without sharing secrets.

Workflow:

  1. The external IdP (e.g., Keycloak) issues a JWT signed with its RSA/ECDSA private key.
  2. Create an APISIX Consumer whose jwt-auth credential has algorithm: RS256 and public_key set to the IdP's corresponding public key in PEM format .
  3. Set key_claim_name on the route to whatever claim the IdP populates (sub, iss, etc.) and ensure a matching Consumer key exists for that value .
  4. APISIX verifies the token's signature via get_auth_secretjwt:verify_jwt_obj.

Note: jwt-auth does not natively support JWKS endpoint discovery. To use a Keycloak JWKS endpoint for dynamic key rotation, use the openid-connect plugin instead — it supports the OIDC discovery document and use_jwks verification.

PEM key format: embed \n after the opening line and before the closing line; key bytes can be concatenated directly .

Token Location and Route-Level Config#

Token lookup order: header → query string → cookie . Route-level options :

FieldDefaultPurpose
headerauthorizationHeader name to read token from
queryjwtQuery param name
cookiejwtCookie name
hide_credentialsfalseStrip token before forwarding upstream
key_claim_namekeyJWT claim used for Consumer lookup
anonymous_consumerFallback Consumer if auth fails
store_in_ctxfalseExpose payload to downstream plugins via ctx.jwt_auth_payload

Bearer prefix in the Authorization header is stripped automatically .

Public Key and Secret Management#

Sensitive fields can be stored outside APISIX config:

  • Environment variables: reference via $env://VAR_NAME in the secret or public_key field .
  • HashiCorp Vault (KV v1): configure an APISIX Secret resource, then reference as $secret://vault/<path> .

The secret field is stored encrypted in etcd via encrypt_fields = {"secret"} .

Claim Verification#

By default, APISIX validates exp and nbf via jwt:get_default_validation_options. The lifetime_grace_period field (seconds) accounts for clock skew between the token issuer and APISIX . The exp default on Consumer credentials is 86400 seconds .

Anonymous Consumer Fallback#

Setting anonymous_consumer on the route allows unauthenticated requests to be mapped to a specific Consumer instead of rejected . This is useful for tiered rate limiting — authenticated consumers get a higher quota, anonymous ones a lower quota .