public-api
The public-api
plugin exposes an internal API endpoint, making it publicly accessible. One of the primary use cases of this plugin is to expose internal endpoint created by other plugins.
Examples
The examples below demonstrate how you can configure public-api
in different scenarios.
Implement JWT for Consumer Authentication
The following example demonstrates how you can expose the JWT signing endpoint /apisix/plugin/jwt/sign
, which is added by the jwt-auth
plugin, and implement JWT for consumer authentication.
Create a route with the public-api
plugin:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "public-jwt-sign",
"uri": "/apisix/plugin/jwt/sign",
"plugins": {
"public-api": {}
}
}'
❶ When the plugin uri
parameter is not configured, the route uri
will be exposed.
Note that at this stage, the jwt-auth
plugin has not been enabled anywhere, so if you send a request to the signing endpoint, you are expected to get a 404 Not Found
.
Create a consumer with jwt-auth
plugin:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jack",
"plugins": {
"jwt-auth": {
"key": "jack-key"
}
}
}'
Create a route with jwt-auth
plugin:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "jwt-route",
"uri": "/headers",
"plugins": {
"jwt-auth": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
Send a request to the signing endpoint to get JWT:
jwt_token=$(curl -s "http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=jack-key") && echo $jwt_token
You should see a token similar to the following:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTAyOTUxMX0.jdZ2iGtXqEMW6QIECTz8CWjBtLt3UMFS9R2j6dVuPJM
Send a request to the route with the JWT in the Authorization
header:
curl -i "http://127.0.0.1:9080/headers" -H "Authorization: ${jwt_token}"
You should receive an HTTP/1.1 200 OK
response similar to the following:
{
"headers": {
"Accept": "*/*",
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY5NTAyOTUxMX0.jdZ2iGtXqEMW6QIECTz8CWjBtLt3UMFS9R2j6dVuPJM",
"Host": "127.0.0.1",
"User-Agent": "curl/7.74.0",
"X-Amzn-Trace-Id": "Root=1-65081904-5a1f18143c29bd2d7d6be0d7",
"X-Forwarded-Host": "127.0.0.1"
}
}
Expose Prometheus Metrics at Custom Endpoint
The following example demonstrates how you can disable the Prometheus export server that, by default, exposes an endpoint on port 9091
, and expose APISIX Prometheus metrics on a new public API endpoint on port 9080
, which APISIX uses to listen to other client requests.
You will also configure the route such that the internal endpoint /apisix/prometheus/metrics
is exposed at a custom endpoint.
If a large quantity of metrics are being collected, the plugin could take up a significant amount of CPU resources for metric computations and negatively impact the processing of regular requests.
To address this issue, APISIX uses privileged agent and offloads the metric computations to a separate process. This optimization applies automatically if you use the metric endpoint configured in the configuration files, as demonstrated above. If you expose the metric endpoint with the public-api
plugin, you will not benefit from this optimization.
Disable the Prometheus export server in the configuration file and reload APISIX for changes to take effect:
plugin_attr:
prometheus:
enable_export_server: false
Next, create a route with public-api
plugin and expose a public API endpoint for APISIX metrics:
curl "http://127.0.0.1:9180/apisix/admin/routes/prometheus-metrics" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/prometheus_metrics",
"plugins": {
"public-api": {
"uri": "/apisix/prometheus/metrics"
}
}
}'
❶ Set the route uri
to the custom endpoint path.
❷ Set the plugin uri
to the internal endpoint to be exposed.
Send a request to the custom metrics endpoint:
curl "http://127.0.0.1:9080/prometheus_metrics"
You should see an output similar to the following:
# HELP apisix_http_requests_total The total number of client requests since APISIX started
# TYPE apisix_http_requests_total gauge
apisix_http_requests_total 1
# HELP apisix_nginx_http_current_connections Number of HTTP connections
# TYPE apisix_nginx_http_current_connections gauge
apisix_nginx_http_current_connections{state="accepted"} 1
apisix_nginx_http_current_connections{state="active"} 1
apisix_nginx_http_current_connections{state="handled"} 1
apisix_nginx_http_current_connections{state="reading"} 0
apisix_nginx_http_current_connections{state="waiting"} 0
apisix_nginx_http_current_connections{state="writing"} 1
...
Protect Public Endpoint with Authentication
The following example demonstrates how you can use an authentication plugin to secure the publicly exposed endpoint.
Before proceeding, please ensure that you have completed the steps in the Implement JWT for Consumer Authentication example, where the jwt-auth
plugin is configured and the signing endpoint is exposed.
Create a consumer with key-auth
plugin:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jwt_sign_admin",
"plugins": {
"key-auth": {
"key": "jwt-sign-admin-pwd"
}
}
}'
Update the route with key-auth
so that only the authenticated requests can access the signing endpoint:
curl "http://127.0.0.1:9180/apisix/admin/routes/public-jwt-sign" -X PATCH \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"plugins": {
"key-auth": {}
}
}'
To verify, send a request to the public signing endpoint without the authentication key:
curl -i "http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=jack-key"
You should receive an HTTP/1.1 401 Unauthorized
response.
Send a request to the public signing endpoint with the authentication key:
curl -i "http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=jack-key" -H "apikey: jwt-sign-admin-pwd"
You should receive an HTTP/1.1 200 OK
response and see a token similar to the following:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MDYzMzQxMjMsImtleSI6ImphY2sta2V5In0.wjSrbMF0JAkJUk5BKFonwkwkeWTKvonKGdhE