key-auth
The key-auth
plugin supports the use of an authentication key as a mechanism for clients to authenticate themselves before accessing upstream resources.
To use the plugin, you would configure authentication keys on consumers and enable the plugin on routes or services. The key can be included in the request URL query string or request header. APISIX will then verify the key to determine if a request should be allowed or denied to access upstream resources.
When a consumer is successfully authenticated, APISIX adds additional headers, such as X-Consumer-Username
, X-Credential-Indentifier
, and other consumer custom headers if configured, to the request, before proxying it to the upstream service. The upstream service will be able to differentiate between consumers and implement additional logics as needed. If any of these values is not available, the corresponding header will not be added.
Examples
The examples below demonstrate how you can work with the key-auth
plugin for different scenarios.
Implement Key Authentication on Route
The following example demonstrates how to implement key authentications on a route and include the key in the request header.
Create a consumer jack
:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack"
}'
Create key-auth
credential for the consumer:
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-jack-key-auth",
"plugins": {
"key-auth": {
"key": "jack-key"
}
}
}'
Create a route with key-auth
:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "key-auth-route",
"uri": "/anything",
"plugins": {
"key-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
Verify with a Valid Key
Send a request to with the valid key:
curl -i "http://127.0.0.1:9080/anything" -H 'apikey: jack-key'
You should receive an HTTP/1.1 200 OK
response.
Verify with an Invalid Key
Send a request with an invalid key:
curl -i "http://127.0.0.1:9080/anything" -H 'apikey: wrong-key'
You should see an HTTP/1.1 401 Unauthorized
response with the following:
{"message":"Invalid API key in request"}
Verify without a Key
Send a request to without a key:
curl -i "http://127.0.0.1:9080/anything"
You should see an HTTP/1.1 401 Unauthorized
response with the following:
{"message":"Missing API key found in request"}
Hide Authentication Information From Upstream
The following example demonstrates how to prevent the key from being sent to the upstream services by configuring hide_credentials
. By default, the authentication key is forwarded to the upstream services, which might lead to security risks in some circumstances.
Create a consumer jack
:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack"
}'
Create key-auth
credential for the consumer:
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-jack-key-auth",
"plugins": {
"key-auth": {
"key": "jack-key"
}
}
}'
Without Hiding Credentials
Create a route with key-auth
and configure hide_credentials
to false
, which is the default configuration:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "key-auth-route",
"uri": "/anything",
"plugins": {
"key-auth": {
"hide_credentials": false
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
Send a request with the valid key:
curl -i "http://127.0.0.1:9080/anything?apikey=jack-key"
You should see an HTTP/1.1 200 OK
response with the following:
{
"args": {
"auth": "jack-key"
},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.2.1",
"X-Consumer-Username": "jack",
"X-Credential-Identifier": "cred-jack-key-auth",
"X-Amzn-Trace-Id": "Root=1-6502d8a5-2194962a67aa21dd33f94bb2",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "127.0.0.1, 103.248.35.179",
"url": "http://127.0.0.1/anything?apikey=jack-key"
}
Note that the credential jack-key
is visible to the upstream service.
Hide Credentials
Update the plugin's hide_credentials
to true
:
curl "http://127.0.0.1:9180/apisix/admin/routes/key-auth-route" -X PATCH \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"plugins": {
"key-auth": {
"hide_credentials": true
}
}
}'
Send a request with the valid key:
curl -i "http://127.0.0.1:9080/anything?apikey=jack-key"
You should see an HTTP/1.1 200 OK
response with the following:
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.2.1",
"X-Consumer-Username": "jack",
"X-Credential-Identifier": "cred-jack-key-auth",
"X-Amzn-Trace-Id": "Root=1-6502d85c-16f34dbb5629a5960183e803",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "127.0.0.1, 103.248.35.179",
"url": "http://127.0.0.1/anything"
}
Note that the credential jack-key
is no longer visible to the upstream service.
Demonstrate Priority of Keys in Header and Query
The following example demonstrates how to implement key authentication by consumers on a route and customize the URL parameter that should include the key. The example also shows that when the API key is configured in both the header and the query string, the request header has a higher priority.
Create a consumer jack
:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack"
}'
Create key-auth
credential for the consumer:
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-jack-key-auth",
"plugins": {
"key-auth": {
"key": "jack-key"
}
}
}'
Create a route with key-auth
:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "key-auth-route",
"uri": "/anything",
"plugins": {
"key-auth": {
"query": "auth"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
Verify with a Valid Key
Send a request to with the valid key:
curl -i "http://127.0.0.1:9080/anything?auth=jack-key"
You should receive an HTTP/1.1 200 OK
response.
Verify with an Invalid Key
Send a request with an invalid key:
curl -i "http://127.0.0.1:9080/anything?auth=wrong-key"
You should see an HTTP/1.1 401 Unauthorized
response with the following:
{"message":"Invalid API key in request"}
Verify with a Valid Key in Query String
However, if you include the valid key in header with the invalid key still in the URL query string:
curl -i "http://127.0.0.1:9080/anything?auth=wrong-key" -H 'apikey: jack-key'
You should see an HTTP/1.1 200 OK
response. This shows that the key included in the header always has a higher priority.
Add Consumer Custom ID to Header
The following example demonstrates how you can attach a consumer custom ID to authenticated request in the Consumer-Custom-Id
header, which can be used to implement additional logics as needed.
Create a consumer jack
with a custom ID label:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack",
"labels": {
"custom_id": "495aec6a"
}
}'
Create key-auth
credential for the consumer:
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-jack-key-auth",
"plugins": {
"key-auth": {
"key": "jack-key"
}
}
}'
Create a route with key-auth
:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "key-auth-route",
"uri": "/anything",
"plugins": {
"key-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
To verify, send a request to the route with the valid key:
curl -i "http://127.0.0.1:9080/anything?auth=jack-key"
You should see an HTTP/1.1 200 OK
response similar to the following:
{
"args": {
"auth": "jack-key"
},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66ea8d64-33df89052ae198a706e18c2a",
"X-Consumer-Username": "jack",
"X-Credential-Identifier": "cred-jack-key-auth",
"X-Consumer-Custom-Id": "495aec6a",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "192.168.65.1, 205.198.122.37",
"url": "http://127.0.0.1/anything?apikey=jack-key"
}
If you would like to attach more consumer custom headers to authenticated requests, see Enterprise attach-consumer-label
plugin.
Rate Limit with Anonymous Consumer
The anonymous consumer is an Enterprise feature.
The following example demonstrates how you can configure different rate limiting policies by regular and anonymous consumers, where the anonymous consumer does not need to authenticate and has less quotas.
Create a regular consumer jack
and configure the limit-count
plugin to allow for a quota of 3 within a 30-second window:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack",
"plugins": {
"limit-count": {
"count": 3,
"time_window": 30,
"rejected_code": 429
}
}
}'
Create the key-auth
credential for the consumer jack
:
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-jack-key-auth",
"plugins": {
"key-auth": {
"key": "jack-key"
}
}
}'
Create an anonymous user anonymous
and configure the limit-count
plugin to allow for a quota of 1 within a 30-second window:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "anonymous",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429
}
}
}'
Create a route and configure the key-auth
plugin to accept anonymous consumer anonymous
from bypassing the authentication:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "key-auth-route",
"uri": "/anything",
"plugins": {
"key-auth": {
"anonymous_consumer": "anonymous"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
To verify, send five consecutive requests with jack
's key:
resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: jack-key' -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
You should see the following response, showing that out of the 5 requests, 3 requests were successful (status code 200) while the others were rejected (status code 429).
200: 3, 429: 2
Send five anonymous requests:
resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429
You should see the following response, showing that only one request was successful:
200: 1, 429: 4