basic-auth
The basic-auth plugin adds basic access authentication for consumers to authenticate themselves before being able to access upstream resources.
When a consumer is successfully authenticated, APISIX adds additional headers, such as X-Consumer-Username, X-Credential-Identifier, 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 basic-auth plugin for different scenarios.
Implement Basic Authentication on Route
The following example demonstrates how to implement basic authentication on a route.
Create a consumer johndoe:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "johndoe"
}'
Create basic-auth credential for the consumer:
curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-john-basic-auth",
"plugins": {
"basic-auth": {
"username": "johndoe",
"password": "john-key"
}
}
}'
Create a route with basic-auth:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "basic-auth-route",
"uri": "/anything",
"plugins": {
"basic-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" -u johndoe:john-key
You should see an HTTP/1.1 200 OK response similar to the following:
{
"args": {},
"headers": {
"Accept": "*/*",
"Apikey": "john-key",
"Authorization": "Basic am9obmRvZTpqb2huLWtleQ==",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66e5107c-5bb3e24f2de5baf733aec1cc",
"X-Consumer-Username": "john",
"X-Credential-Identifier": "cred-john-basic-auth",
"X-Forwarded-Host": "127.0.0.1"
},
"origin": "192.168.65.1, 205.198.122.37",
"url": "http://127.0.0.1/get"
}
Verify with an Invalid Key
Send a request with an invalid key:
curl -i "http://127.0.0.1:9080/anything" -u johndoe:invalid-key
You should see an HTTP/1.1 401 Unauthorized response with the following:
{"message":"Invalid user authorization"}
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 authorization 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. If you are using APISIX, the authentication key is forwarded to the upstream services by default, which might lead to security risks in some circumstances and you should consider updating hide_credentials as shown in this example.
Create a consumer johndoe:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "johndoe"
}'
Create basic-auth credential for the consumer:
curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-john-basic-auth",
"plugins": {
"basic-auth": {
"username": "johndoe",
"password": "john-key"
}
}
}'
Without Hiding Credentials
Create a route with basic-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": "basic-auth-route",
"uri": "/anything",
"plugins": {
"basic-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" -u johndoe:john-key
You should see an HTTP/1.1 200 OK response with the following:
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Authorization": "Basic am9obmRvZTpqb2huLWtleQ==",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66cc2195-22bd5f401b13480e63c498c6",
"X-Consumer-Username": "john",
"X-Credential-Identifier": "cred-john-basic-auth",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "192.168.65.1, 43.228.226.23",
"url": "http://127.0.0.1/anything"
}
Note that the credentials are visible to the upstream service in base64-encoded format.
You can also pass the base64-encoded credentials in the request using the Authorization header as such:
curl -i "http://127.0.0.1:9080/anything" -H "Authorization: Basic am9obmRvZTpqb2huLWtleQ=="
Hide Credentials
Update the plugin's hide_credentials to true:
curl "http://127.0.0.1:9180/apisix/admin/routes/basic-auth-route" -X PATCH \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"plugins": {
"basic-auth": {
"hide_credentials": true
}
}
}'
Send a request with the valid key:
curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-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.6.0",
"X-Amzn-Trace-Id": "Root=1-66cc21a7-4f6ac87946e25f325167d53a",
"X-Consumer-Username": "john",
"X-Credential-Identifier": "cred-john-basic-auth",
"X-Forwarded-Host": "127.0.0.1"
},
"json": null,
"method": "GET",
"origin": "192.168.65.1, 43.228.226.23",
"url": "http://127.0.0.1/anything"
}
Note that the credentials are no longer visible to the upstream service.
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 johndoe 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": "johndoe",
"labels": {
"custom_id": "495aec6a"
}
}'
Create basic-auth credential for the consumer:
curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-john-basic-auth",
"plugins": {
"basic-auth": {
"username": "johndoe",
"password": "john-key"
}
}
}'
Create a route with basic-auth:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "basic-auth-route",
"uri": "/anything",
"plugins": {
"basic-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" -u johndoe:john-key
You should see an HTTP/1.1 200 OK response similar to the following:
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Authorization": "Basic am9obmRvZTpqb2huLWtleQ==",
"Host": "127.0.0.1",
"User-Agent": "curl/8.6.0",
"X-Amzn-Trace-Id": "Root=1-66ea8d64-33df89052ae198a706e18c2a",
"X-Consumer-Username": "johndoe",
"X-Credential-Identifier": "cred-john-basic-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"
}
If you would like to attach more consumer custom headers to authenticated requests, see the attach-consumer-label plugin.
Rate Limit with Anonymous Consumer
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 johndoe 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": "johndoe",
"plugins": {
"limit-count": {
"count": 3,
"time_window": 30,
"rejected_code": 429
}
}
}'
Create the basic-auth credential for the consumer johndoe:
curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-john-basic-auth",
"plugins": {
"basic-auth": {
"username": "johndoe",
"password": "john-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 basic-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": "basic-auth-route",
"uri": "/anything",
"plugins": {
"basic-auth": {
"anonymous_consumer": "anonymous"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
To verify, send five consecutive requests with john's key:
resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -u johndoe:john-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