AWS API Gateway mTLS: Setup, Test, And Troubleshoot
Securing API endpoints with AWS API Gateway mTLS adds a critical layer of trust to your infrastructure, both the client and server verify each other's identity before any data moves. For healthcare applications handling protected health information, this isn't optional; it's a baseline security requirement that supports HIPAA compliance and builds confidence with EHR partners.
At SoFaaS, we build managed SMART on FHIR integrations that connect healthcare applications to EHR systems like Epic and Cerner. Mutual TLS is baked into how we secure those connections, and we've configured, debugged, and scaled it across production environments serving real patient data. That hands-on experience is exactly what informed this guide.
Below, you'll walk through the full process: generating certificates, configuring a custom domain with mTLS on API Gateway, testing your setup with curl, and diagnosing the most common errors that trip teams up. Whether you're protecting a healthcare API or any other sensitive workload, every step applies directly.
What you need before you enable mTLS
Before you touch API Gateway settings, make sure your environment is ready. AWS API Gateway mTLS requires several components that work together, and missing any one of them will block your setup at a later step. Getting these in place upfront saves you from backtracking mid-configuration.
mTLS on API Gateway only works with custom domain names. The default execute-api endpoint does not support mutual TLS authentication.
AWS account access and tooling
You need IAM permissions that cover API Gateway, ACM (AWS Certificate Manager), S3, and Route 53 or your DNS provider. Without the right access, you will hit permission errors at multiple points during setup.
Install and configure the AWS CLI on your local machine before you start. You also need OpenSSL installed locally to generate certificate authority (CA) keys, issue client certificates, and build the truststore bundle that API Gateway will reference.
Custom domain, ACM certificate, and S3 truststore
Your setup requires three specific AWS resources before you enable mTLS:
- Custom domain name: A domain you control (e.g.,
api.yourcompany.com) registered in API Gateway. The default execute-api endpoint does not support mTLS. - ACM certificate: An SSL/TLS certificate issued or imported in AWS Certificate Manager that covers your custom domain.
- S3 truststore object: A PEM-formatted file containing your CA certificate(s), uploaded to an S3 bucket. API Gateway reads this file to validate incoming client certificates.
Make sure S3 bucket versioning is enabled on the bucket holding your truststore. API Gateway references a specific S3 object version, so versioning lets you update the truststore without taking your API offline.
Step 1. Plan your certificates and truststore
Planning your certificate structure upfront saves you from configuration mismatches that are painful to unravel later. For AWS API Gateway mTLS, you need two artifacts: a CA certificate that becomes your truststore and a client certificate signed by that CA. API Gateway uses the truststore to verify every incoming client connection, so getting this structure right before you configure anything is essential.

Generate a self-signed CA and client certificate
Use OpenSSL to create your CA key and certificate, then issue a client certificate signed by that CA. Run these commands in sequence:
# Create CA key and self-signed certificate
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 365 -key ca.key -out ca.pem -subj "/CN=MyCA"
# Create client key and certificate signing request
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr -subj "/CN=MyClient"
# Sign the client certificate with your CA
openssl x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out client.pem
The
ca.pemfile is your truststore. API Gateway reads it to validate every client certificate presented during the TLS handshake.
Once you have both files, upload ca.pem to your S3 bucket and record the object version ID before moving to Step 2.
Step 2. Configure API Gateway mTLS on a custom domain
With your truststore uploaded, you're ready to wire AWS API Gateway mTLS to your custom domain name. This step ties your S3 truststore to the domain configuration and activates mutual TLS enforcement for every incoming client connection. Without this linkage, API Gateway has nothing to validate client certificates against.
Attach the truststore to your custom domain
Run the following AWS CLI command to update your custom domain with mTLS enabled, referencing the S3 truststore and the version ID you recorded in Step 1:
aws apigatewayv2 update-domain-name \
--domain-name api.yourcompany.com \
--domain-name-configurations CertificateArn=arn:aws:acm:us-east-1:123456789012:certificate/abc-123 \
--mutual-tls-authentication TruststoreUri=s3://your-bucket/ca.pem,TruststoreVersion=your-version-id
Always pin the truststore to a specific S3 object version so a bucket update does not silently change your trust anchor.
Your domain configuration now requires every client to present a certificate signed by your CA. Verify that the update returned AVAILABLE in the DomainNameStatus field before continuing. If the status shows UPDATING, wait a minute and rerun aws apigatewayv2 get-domain-name --domain-name api.yourcompany.com to confirm the change is live.
Step 3. Disable the execute endpoint and deploy
Enabling mTLS on your custom domain does not automatically close the back door. API Gateway keeps the default execute-api endpoint active, and clients can bypass your mutual TLS requirement entirely by calling that URL directly. You must disable it explicitly before your security enforcement is complete.
Skipping this step leaves an unauthenticated route into your API even after mTLS is configured on the custom domain.
Disable the default execute-api endpoint
Set DisableExecuteApiEndpoint to true on your REST or HTTP API using the AWS CLI. For an HTTP API, run:
aws apigatewayv2 update-api \
--api-id your-api-id \
--disable-execute-api-endpoint
Confirm the response shows "DisableExecuteApiEndpoint": true before continuing. Any request hitting the raw execute-api URL after this change returns a 403 Forbidden response.
Deploy your API stage
After disabling the endpoint, deploy your API stage so the configuration takes effect in production:
aws apigatewayv2 create-deployment \
--api-id your-api-id \
--stage-name prod
Your aws api gateway mtls setup is now fully enforced through the custom domain only.
Step 4. Test mTLS and log identity
With your aws api gateway mtls configuration deployed, you need to verify that the mutual TLS handshake actually works before shipping to production. Testing both the success and rejection paths confirms your setup behaves exactly as expected.
Send a test request with curl
Use curl to send a request to your custom domain, presenting the client certificate and key you generated in Step 1:
curl -v --cert client.pem --key client.key https://api.yourcompany.com/your-resource
Then confirm that unauthenticated requests are rejected by running curl without the certificate flags. You should receive a 403 Forbidden response immediately.
A successful handshake returns your API response; a missing or untrusted certificate returns 403 before your backend ever receives the request.
Log the client certificate identity
API Gateway passes client certificate metadata through the $context.identity.clientCert context variable. Add this variable to your access log format in the stage settings so every request records the certificate's subject and serial number for audit purposes.
Troubleshoot API Gateway mTLS errors
When your aws api gateway mtls setup breaks, the error typically traces back to one of three sources: a malformed truststore, a certificate chain mismatch, or a stale S3 version ID. Identifying which symptom maps to which root cause cuts your debugging time significantly and keeps your team from chasing the wrong fix.

Check CloudWatch access logs first; the
$context.identity.clientCertvariable often reveals exactly which certificate validation step failed.
Common errors and their fixes
Each of the errors below surfaces at a specific point in the mTLS handshake or configuration process, so matching the symptom to the right fix is straightforward once you know what to look for.
| Error | Root Cause | Fix |
|---|---|---|
TruststoreWarnings on domain update |
Invalid PEM format in truststore | Re-export ca.pem with openssl x509 and re-upload |
403 with valid client cert |
Wrong S3 version ID pinned | Update domain with the current version ID |
SSL handshake failed on curl |
Client cert not signed by trusted CA | Verify chain with openssl verify -CAfile ca.pem client.pem |

Key takeaways
Setting up aws api gateway mtls comes down to four decisions executed in the right order: build a clean certificate chain, attach your truststore to a custom domain, disable the default execute-api endpoint, and test both the success and failure paths before you call it done. Each step depends on the one before it, so skipping ahead creates gaps that are hard to trace once you're in production.
Healthcare APIs carry a higher burden here. HIPAA-regulated data moves through these connections, and mTLS gives you verifiable identity at the transport layer, not just at the application layer. Log the $context.identity.clientCert variable on every request so your audit trail reflects who connected and when.
Building a SMART on FHIR application that needs secure EHR connectivity without managing all this infrastructure yourself is exactly the problem SoFaaS solves. See how SoFaaS handles SMART on FHIR integration for you.
The Future of Patient Logistics
Exploring the future of all things related to patient logistics, technology and how AI is going to re-shape the way we deliver care.