skills/a6-plugin-jwt-auth/SKILL.md
Skill for configuring the Apache APISIX jwt-auth plugin via the a6 CLI. Covers JWT token authentication, HS256/RS256 algorithm selection, consumer credential binding, token lookup from header/query/cookie, claims handling, clock skew, secret management, and common operational patterns.
npx skillsauth add moonming/a6 a6-plugin-jwt-authInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The jwt-auth plugin authenticates requests using JSON Web Tokens. Consumers
register a key and secret (or public key for asymmetric algorithms). Clients
include a signed JWT in the request header, query parameter, or cookie. APISIX
validates the signature and claims, then forwards the request with consumer
identity headers.
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| key | string | Yes | — | Unique identifier in JWT payload to match consumer |
| secret | string | Conditional | — | Shared secret for HMAC algorithms (HS256/HS384/HS512). Encrypted in etcd. |
| public_key | string | Conditional | — | PEM public key for RSA/ECDSA/EdDSA algorithms |
| algorithm | string | No | "HS256" | Signing algorithm (see supported list below) |
| exp | integer | No | 86400 | Token lifetime in seconds (not UNIX timestamp) |
| base64_secret | boolean | No | false | Set true if secret is base64-encoded |
| lifetime_grace_period | integer | No | 0 | Clock skew tolerance in seconds |
| key_claim_name | string | No | "key" | JWT claim containing the consumer key |
| Family | Algorithms | |--------|-----------| | HMAC | HS256, HS384, HS512 | | RSA | RS256, RS384, RS512 | | RSA-PSS | PS256, PS384, PS512 | | ECDSA | ES256, ES384, ES512 | | EdDSA | EdDSA |
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| header | string | No | "authorization" | Header to extract JWT from |
| query | string | No | "jwt" | Query parameter to extract JWT from |
| cookie | string | No | "jwt" | Cookie to extract JWT from |
| hide_credentials | boolean | No | false | Remove JWT before forwarding upstream |
| key_claim_name | string | No | "key" | JWT claim containing consumer key (must match credential config) |
| anonymous_consumer | string | No | — | Consumer for unauthenticated requests |
| claims_to_verify | array | No | ["exp","nbf"] | Claims to verify (exp, nbf) |
authorization) — supports Bearer <token> prefixjwt)jwt)a6 consumer create -f - <<'EOF'
{
"username": "alice"
}
EOF
curl "$(a6 context current -o json | jq -r .server)/apisix/admin/consumers/alice/credentials" \
-X PUT \
-H "X-API-KEY: $(a6 context current -o json | jq -r .api_key)" \
-d '{
"id": "cred-alice-jwt",
"plugins": {
"jwt-auth": {
"key": "alice-key",
"secret": "alice-secret-minimum-32-chars-long",
"algorithm": "HS256",
"exp": 86400
}
}
}'
a6 route create -f - <<'EOF'
{
"id": "jwt-protected",
"uri": "/api/*",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF
Create a JWT with payload {"key": "alice-key", "exp": <future_timestamp>}
signed with alice-secret-minimum-32-chars-long using HS256.
curl -i http://127.0.0.1:9080/api/test \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..."
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -pubout -out public.pem
curl "$(a6 context current -o json | jq -r .server)/apisix/admin/consumers/bob/credentials" \
-X PUT \
-H "X-API-KEY: $(a6 context current -o json | jq -r .api_key)" \
-d '{
"id": "cred-bob-jwt",
"plugins": {
"jwt-auth": {
"key": "bob-key",
"algorithm": "RS256",
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjAN...\n-----END PUBLIC KEY-----"
}
}
}'
Sign tokens with private.pem externally. APISIX only needs the public key.
iss instead of key)# Credential config:
{
"jwt-auth": {
"key": "my-issuer-id",
"secret": "my-secret",
"key_claim_name": "iss"
}
}
# Route config:
{
"jwt-auth": {
"key_claim_name": "iss"
}
}
# JWT payload:
{
"iss": "my-issuer-id",
"exp": 1879318541
}
{
"jwt-auth": {
"key": "consumer-key",
"secret": "my-secret",
"lifetime_grace_period": 30
}
}
Allows 30 seconds clock drift between token issuer and APISIX.
{
"plugins": {
"jwt-auth": {
"query": "token"
}
}
}
Client sends: curl "http://127.0.0.1:9080/api/test?token=eyJ..."
{
"jwt-auth": {
"key": "consumer-key",
"secret": "$env://JWT_SECRET"
}
}
{
"jwt-auth": {
"key": "consumer-key",
"secret": "$secret://vault/jwt/consumer-name/jwt-secret"
}
}
| Header | Value |
|--------|-------|
| X-Consumer-Username | Consumer's username |
| X-Credential-Identifier | Credential ID |
| X-Consumer-Custom-Id | Consumer's labels.custom_id (if set) |
| HTTP Code | Message | Cause |
|-----------|---------|-------|
| 401 | "Missing JWT token in request" | No token in header/query/cookie |
| 401 | "JWT token invalid" | Malformed token |
| 401 | "failed to verify jwt" | Bad signature, expired, or invalid claims |
| 401 | "Invalid user key in JWT token" | Consumer key not found |
| Symptom | Cause | Fix |
|---------|-------|-----|
| 401 "failed to verify jwt" | Token expired | Generate new token with future exp |
| 401 "failed to verify jwt" | Algorithm mismatch | Ensure credential algorithm matches token |
| 401 "Invalid user key" | Wrong claim name | Set key_claim_name on both credential and route |
| Public key rejected | Missing newlines in PEM | Include \n after header/before footer lines |
| Clock skew errors | Time drift | Set lifetime_grace_period on credential |
version: "1"
consumers:
- username: alice
routes:
- id: jwt-protected
uri: /api/*
plugins:
jwt-auth: {}
upstream_id: my-upstream
upstreams:
- id: my-upstream
type: roundrobin
nodes:
"backend:8080": 1
Note: Consumer credentials (including JWT keys/secrets) must be created separately via the Admin API;
a6 config syncmanages the consumer resource but credentials are sub-resources.
tools
Core skill for working with the a6 CLI — the Apache APISIX command-line tool. Provides project conventions, command patterns, architecture overview, and development workflow. Load this skill when working on a6 source code, adding new commands, writing tests, or modifying any a6 component.
tools
Recipe skill for implementing multi-tenant API gateway patterns using the a6 CLI. Covers tenant isolation via Consumer Groups, host/path/header-based routing, per-tenant rate limiting, context forwarding with proxy-rewrite, and declarative config sync workflows for multi-tenant management.
tools
Recipe skill for configuring mutual TLS (mTLS) using the a6 CLI. Covers SSL certificate management, upstream mTLS to backend services, client certificate verification, and end-to-end mTLS setup from client through APISIX to upstream.
tools
Recipe skill for configuring upstream health checks using the a6 CLI. Covers active health checks (HTTP probing), passive health checks (response analysis), combining both, configuring healthy/unhealthy thresholds, and monitoring upstream node status.