Skip to main content

Version: latest

Client mTLS Authentication

Mutual TLS (mTLS) extends standard TLS by requiring both the client and the server to present certificates during the TLS handshake. This provides cryptographic proof of client identity and is suitable for zero-trust architectures, machine-to-machine communication, and environments where API key or token authentication is not enough on its own.

In API7 Gateway, client mTLS is configured on an SSL object that binds the listener domain (SNI) to a server certificate, a private key, and the CA certificates used to verify clients. When mTLS is enabled, the gateway requires the client to present a certificate signed by one of the configured CAs before the TLS handshake completes.

info

This page covers mTLS between API clients and the gateway. For mTLS between the Control Plane and Data Plane, see Mutual TLS between CP and DP. For mTLS between the gateway and upstream servers, see Upstream mTLS.

How it works

  1. A client initiates a TLS connection to the gateway and includes the target domain in the SNI extension of the ClientHello.
  2. The gateway matches the SNI to an SSL object that has client mTLS configured.
  3. The gateway presents its server certificate and asks the client for a certificate.
  4. The client presents its certificate. The gateway validates the chain against the configured CA.
  5. If validation succeeds, the TLS handshake completes and the request is forwarded to the upstream. If validation fails, the connection is rejected at the TLS layer.

Prerequisites

Prepare the following PEM-encoded certificates:

CertificatePurpose
Server certificate + private keyPresented by the gateway to clients.
CA certificateUsed by the gateway to verify client certificates.
Client certificate + private keyPresented by clients to the gateway. Must be signed by the CA above.

If you do not have a set of certificates for testing, generate one with:

# Generate CA
openssl req -x509 -newkey rsa:2048 -keyout ca.key -out ca.crt -days 365 -nodes \
-subj "/CN=Test CA"

# Generate server certificate
openssl req -newkey rsa:2048 -keyout server.key -out server.csr -nodes \
-subj "/CN=api.example.com"
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt -days 365

# Generate client certificate
openssl req -newkey rsa:2048 -keyout client.key -out client.csr -nodes \
-subj "/CN=test-client"
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out client.crt -days 365

You also need a route to send traffic through. The example below uses an httpbin.org service with a route on /anything.

Configure client mTLS

Step 1: Create a service and route

Client mTLS is enforced during the TLS handshake based on SNI selection, before any routing decision. A route is not required to verify the handshake itself, but you need one to receive a meaningful HTTP response from an upstream. Create a minimal service and route first.

# Create the service with the upstream
curl -k "https://localhost:7443/apisix/admin/services/httpbin?gateway_group_id={group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "httpbin",
"upstream": {
"type": "roundrobin",
"scheme": "http",
"nodes": [
{ "host": "httpbin.org", "port": 80, "weight": 1 }
]
}
}'

# Create the route under that service
curl -k "https://localhost:7443/apisix/admin/routes/get-anything?gateway_group_id={group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "get-anything",
"service_id": "httpbin",
"paths": ["/anything"],
"methods": ["GET"]
}'

Replace {group_id} with your gateway group ID — use default for the gateway group created by the quickstart.

Step 2: Create the SSL object with client mTLS enabled

Create an SSL object that binds the SNI (api.example.com), the server certificate and key, and the CA used to verify client certificates. Setting the client.ca field is what enables client mTLS for that SNI.

SERVER_CRT=$(awk 1 ORS='\\n' server.crt)
SERVER_KEY=$(awk 1 ORS='\\n' server.key)
CA_CRT=$(awk 1 ORS='\\n' ca.crt)

curl -k "https://localhost:7443/apisix/admin/ssls/client-mtls-ssl?gateway_group_id={group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"snis\": [\"api.example.com\"],
\"cert\": \"${SERVER_CRT}\",
\"key\": \"${SERVER_KEY}\",
\"client\": {
\"ca\": \"${CA_CRT}\"
}
}"

The awk 1 ORS='\\n' invocations preserve the multi-line PEM contents inside the JSON body by escaping newlines.

Step 3: Verify

Send a request that includes a valid client certificate. The gateway listens for HTTPS traffic on port 9443.

curl --cacert ca.crt --cert client.crt --key client.key \
--resolve api.example.com:9443:127.0.0.1 \
https://api.example.com:9443/anything

You should receive a 200 OK response and the JSON body from httpbin.org.

Send the same request without a client certificate. The TLS handshake should fail before any HTTP request is sent:

curl --cacert ca.crt \
--resolve api.example.com:9443:127.0.0.1 \
https://api.example.com:9443/anything

curl exits with an SSL error and the gateway error log records SSL_do_handshake() failed (... peer did not return a certificate).

Reference certificates from a secret provider

Instead of embedding PEM material directly in the SSL object, you can reference certificates stored in HashiCorp Vault, AWS Secrets Manager, or Kubernetes Secrets using the $secret://... URI format. See Secure Credentials for the available providers and the URI shape for each one.

Security considerations

  • Host header validation. When mTLS is enabled, the gateway verifies that the HTTP Host header matches the SNI used during the TLS handshake. If they differ and the two domains have mTLS enabled with different CA certificates, the request is rejected to prevent certificate confusion attacks.
  • TLS session resumption. The gateway validates that resumed TLS sessions match the original SNI, so a session ticket cannot be reused against a different SNI to bypass mTLS.
  • Certificate rotation. Plan for CA and client certificate rotation before expiry. During a CA rotation, configure the SSL object's client.ca to contain both the old and new CA bundles concatenated together so that clients on either CA can connect.

Next steps

API7.ai Logo

The digital world is connected by APIs,
API7.ai exists to make APIs more efficient, reliable, and secure.

Sign up for API7 newsletter

Product

API7 Gateway

SOC2 Type IIISO 27001HIPAAGDPRRed Herring

Copyright © APISEVEN PTE. LTD 2019 – 2026. Apache, Apache APISIX, APISIX, and associated open source project names are trademarks of the Apache Software Foundation