title: basic-auth keywords:
import Tabs from ‘@theme/Tabs’; import TabItem from ‘@theme/TabItem’;
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.
For Consumer/Credentials:
| Name | Type | Required | Default | Valid values | Description |
|---|---|---|---|---|---|
| username | string | True | Unique basic auth username for a Consumer. | ||
| password | string | True | Basic auth password for the Consumer. The password is encrypted with AES before being stored in etcd. You can also store it in an environment variable and reference it using the env:// prefix, or in a secret manager such as HashiCorp Vault's KV secrets engine, and reference it using the secret:// prefix. |
For Route:
| Name | Type | Required | Default | Valid values | Description |
|---|---|---|---|---|---|
| hide_credentials | boolean | False | false | If true, do not pass the authorization request header to Upstream services. | |
| anonymous_consumer | string | False | Anonymous Consumer name. If configured, allow anonymous users to bypass the authentication. | ||
| realm | string | False | basic | Realm in the WWW-Authenticate response header returned with a 401 Unauthorized response due to authentication failure. Available in Apache APISIX version 3.15.0 and later. |
The examples below demonstrate how you can work with the basic-auth Plugin for different scenarios.
:::note
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')
:::
The following example demonstrates how to implement basic authentication on a Route.
<Tabs groupId=“api” defaultValue=“admin-api” values={[ {label: ‘Admin API’, value: ‘admin-api’}, {label: ‘ADC’, value: ‘adc’}, {label: ‘Ingress Controller’, value: ‘aic’} ]}>
Create a Consumer johndoe:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${admin_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_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_key}" \ -d '{ "id": "basic-auth-route", "uri": "/anything", "plugins": { "basic-auth": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }'
Create a Consumer with basic-auth Credential and a Route with basic-auth Plugin configured:
consumers: - username: johndoe credentials: - name: basic-auth type: basic-auth config: username: johndoe password: john-key services: - name: basic-auth-service routes: - name: basic-auth-route uris: - /anything plugins: basic-auth: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1
Synchronize the configuration to the gateway:
adc sync -f adc.yaml
Create a Consumer with basic-auth Credential and a Route with basic-auth Plugin configured:
<Tabs groupId=“k8s-api” defaultValue=“gateway-api” values={[ {label: ‘Gateway API’, value: ‘gateway-api’}, {label: ‘APISIX Ingress Controller’, value: ‘apisix-ingress-controller’} ]}>
apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: johndoe spec: gatewayRef: name: apisix credentials: - type: basic-auth name: primary-cred config: username: johndoe password: john-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: basic-auth-plugin-config spec: plugins: - name: basic-auth config: _meta: disable: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: basic-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: basic-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80
Apply the configuration to your cluster:
kubectl apply -f basic-auth-ic.yaml
apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: johndoe spec: ingressClassName: apisix authParameter: basicAuth: value: username: johndoe password: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: basic-auth-route spec: ingressClassName: apisix http: - name: basic-auth-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: basic-auth enable: true
Apply the configuration to your cluster:
kubectl apply -f basic-auth-ic.yaml
Send a request to the Route with valid Credentials:
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": "*/*", "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": "johndoe", "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/anything" }
Send a request with invalid Credentials:
curl -i "http://127.0.0.1:9080/anything" -u johndoe:invalid-password
You should see an HTTP/1.1 401 Unauthorized response with the following:
{"message":"Invalid user authorization"}
Send a request without Credentials:
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"}
The following example demonstrates how to prevent the client‘s Credentials (the Authorization header) from being sent to the Upstream services by configuring hide_credentials. If you are using APISIX, the Authorization header containing the client’s Credentials 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.
<Tabs groupId=“api” defaultValue=“admin-api” values={[ {label: ‘Admin API’, value: ‘admin-api’}, {label: ‘ADC’, value: ‘adc’}, {label: ‘Ingress Controller’, value: ‘aic’} ]}>
Create a Consumer johndoe:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ -H "X-API-KEY: ${admin_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_key}" \ -d '{ "id": "cred-john-basic-auth", "plugins": { "basic-auth": { "username": "johndoe", "password": "john-key" } } }'
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_key}" \ -d '{ "id": "basic-auth-route", "uri": "/anything", "plugins": { "basic-auth": { "hide_credentials": false } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }'
Create a Consumer with basic-auth Credential and a Route with basic-auth Plugin configured:
consumers: - username: johndoe credentials: - name: basic-auth type: basic-auth config: username: johndoe password: john-key services: - name: basic-auth-service routes: - name: basic-auth-route uris: - /anything plugins: basic-auth: hide_credentials: false upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1
Synchronize the configuration to the gateway:
adc sync -f adc.yaml
Create a Consumer with basic-auth Credential and a Route with basic-auth Plugin configured:
<Tabs groupId=“k8s-api” defaultValue=“gateway-api” values={[ {label: ‘Gateway API’, value: ‘gateway-api’}, {label: ‘APISIX Ingress Controller’, value: ‘apisix-ingress-controller’} ]}>
apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: johndoe spec: gatewayRef: name: apisix credentials: - type: basic-auth name: primary-cred config: username: johndoe password: john-key --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: basic-auth-plugin-config spec: plugins: - name: basic-auth config: _meta: disable: false hide_credentials: false --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: basic-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: basic-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80
Apply the configuration to your cluster:
kubectl apply -f basic-auth-ic.yaml
apiVersion: apisix.apache.org/v2 kind: ApisixConsumer metadata: namespace: aic name: johndoe spec: ingressClassName: apisix authParameter: basicAuth: value: username: johndoe password: john-key --- apiVersion: apisix.apache.org/v2 kind: ApisixUpstream metadata: namespace: aic name: httpbin-external-domain spec: ingressClassName: apisix externalNodes: - type: Domain name: httpbin.org --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: basic-auth-route spec: ingressClassName: apisix http: - name: basic-auth-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: basic-auth enable: true config: hide_credentials: false
Apply the configuration to your cluster:
kubectl apply -f basic-auth-ic.yaml
Send a request with the valid Credentials:
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": "johndoe", "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:
curl -i "http://127.0.0.1:9080/anything" -H "Authorization: Basic am9obmRvZTpqb2huLWtleQ=="
<Tabs groupId=“api” defaultValue=“admin-api” values={[ {label: ‘Admin API’, value: ‘admin-api’}, {label: ‘ADC’, value: ‘adc’}, {label: ‘Ingress Controller’, value: ‘aic’} ]}>
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_key}" \ -d '{ "plugins": { "basic-auth": { "hide_credentials": true } } }'
Update the Route configuration:
# other configs # ... services: - name: basic-auth-service routes: - name: basic-auth-route uris: - /anything plugins: basic-auth: hide_credentials: true upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1
Synchronize the configuration to the gateway:
adc sync -f adc.yaml
<Tabs groupId=“k8s-api” defaultValue=“gateway-api” values={[ {label: ‘Gateway API’, value: ‘gateway-api’}, {label: ‘APISIX Ingress Controller’, value: ‘apisix-ingress-controller’} ]}>
Update the PluginConfig to set hide_credentials to true:
# other configs # --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: basic-auth-plugin-config spec: plugins: - name: basic-auth config: _meta: disable: false hide_credentials: true
Apply the configuration to your cluster:
kubectl apply -f basic-auth-ic.yaml
Update the ApisixRoute to set hide_credentials to true:
# other configs # --- apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: namespace: aic name: basic-auth-route spec: ingressClassName: apisix http: - name: basic-auth-route match: paths: - /anything upstreams: - name: httpbin-external-domain plugins: - name: basic-auth enable: true config: hide_credentials: true
Apply the configuration to your cluster:
kubectl apply -f basic-auth-ic.yaml
Send a request with the valid Credentials:
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": "johndoe", "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.
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.
<Tabs groupId=“api” defaultValue=“admin-api” values={[ {label: ‘Admin API’, value: ‘admin-api’}, {label: ‘ADC’, value: ‘adc’}, {label: ‘Ingress Controller’, value: ‘aic’} ]}>
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_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_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_key}" \ -d '{ "id": "basic-auth-route", "uri": "/anything", "plugins": { "basic-auth": {} }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }'
Create a Consumer with basic-auth Credential and a Route with basic-auth Plugin enabled:
consumers: - username: johndoe labels: custom_id: "495aec6a" credentials: - name: basic-auth type: basic-auth config: username: johndoe password: john-key services: - name: basic-auth-service routes: - name: basic-auth-route uris: - /anything plugins: basic-auth: {} upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1
Synchronize the configuration to the gateway:
adc sync -f adc.yaml
Consumer custom labels are currently not supported when configuring resources through the Ingress Controller, and the X-Consumer-Custom-Id header is not included in requests. At the moment, this example cannot be completed with the Ingress Controller.
To verify, send a request to the Route with the valid Credentials:
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" }
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 quota.
<Tabs groupId=“api” defaultValue=“admin-api” values={[ {label: ‘Admin API’, value: ‘admin-api’}, {label: ‘ADC’, value: ‘adc’}, {label: ‘Ingress Controller’, value: ‘aic’} ]}>
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_key}" \ -d '{ "username": "johndoe", "plugins": { "limit-count": { "count": 3, "time_window": 30, "rejected_code": 429, "policy": "local" } } }'
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_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_key}" \ -d '{ "username": "anonymous", "plugins": { "limit-count": { "count": 1, "time_window": 30, "rejected_code": 429, "policy": "local" } } }'
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_key}" \ -d '{ "id": "basic-auth-route", "uri": "/anything", "plugins": { "basic-auth": { "anonymous_consumer": "anonymous" } }, "upstream": { "type": "roundrobin", "nodes": { "httpbin.org:80": 1 } } }'
Configure Consumers with different rate limits and a Route that accepts anonymous users:
consumers: - username: johndoe plugins: limit-count: count: 3 time_window: 30 rejected_code: 429 policy: local credentials: - name: basic-auth type: basic-auth config: username: johndoe password: john-key - username: anonymous plugins: limit-count: count: 1 time_window: 30 rejected_code: 429 policy: local services: - name: anonymous-rate-limit-service routes: - name: basic-auth-route uris: - /anything plugins: basic-auth: anonymous_consumer: anonymous upstream: type: roundrobin nodes: - host: httpbin.org port: 80 weight: 1
Synchronize the configuration to the gateway:
adc sync -f adc.yaml
<Tabs groupId=“k8s-api” defaultValue=“gateway-api” values={[ {label: ‘Gateway API’, value: ‘gateway-api’}, {label: ‘APISIX Ingress Controller’, value: ‘apisix-ingress-controller’} ]}>
Configure Consumers with different rate limits and a Route that accepts anonymous users:
apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: johndoe spec: gatewayRef: name: apisix credentials: - type: basic-auth name: primary-key config: username: johndoe password: john-key plugins: - name: limit-count config: count: 3 time_window: 30 rejected_code: 429 policy: local --- apiVersion: apisix.apache.org/v1alpha1 kind: Consumer metadata: namespace: aic name: anonymous spec: gatewayRef: name: apisix plugins: - name: limit-count config: count: 1 time_window: 30 rejected_code: 429 policy: local --- apiVersion: v1 kind: Service metadata: namespace: aic name: httpbin-external-domain spec: type: ExternalName externalName: httpbin.org --- apiVersion: apisix.apache.org/v1alpha1 kind: PluginConfig metadata: namespace: aic name: basic-auth-plugin-config spec: plugins: - name: basic-auth config: anonymous_consumer: aic_anonymous # namespace_consumername --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: namespace: aic name: basic-auth-route spec: parentRefs: - name: apisix rules: - matches: - path: type: Exact value: /anything filters: - type: ExtensionRef extensionRef: group: apisix.apache.org kind: PluginConfig name: basic-auth-plugin-config backendRefs: - name: httpbin-external-domain port: 80
Apply the configuration to your cluster:
kubectl apply -f basic-auth-ic.yaml
The ApisixConsumer CRD currently does not support configuring plugins on consumers, except for the authentication plugins allowed in authParameter. This example cannot be completed with APISIX CRDs.
To verify, send five consecutive requests with johndoe's Credentials:
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