Mutual TLS (mTLS) Certificate Guide

Mutual TLS requires both server and client to present X.509 certificates. Learn mTLS certificate requirements, server configuration, service mesh SPIFFE SVIDs, and debugging.

Mutual TLS (mTLS) Certificate Guide

Mutual TLS (mTLS) requires both the server and the client to present X.509 certificates during the TLS handshake, providing bidirectional cryptographic authentication. In standard TLS, only the server presents a certificate; the client verifies the server's identity but the server has no cryptographic proof of the client's identity. In mTLS, the server sends a CertificateRequest message during the handshake, the client responds with its own certificate, and the server verifies that certificate against its configured CA trust store. Consequently, only clients holding a certificate signed by a trusted CA can complete the handshake at all, regardless of any credentials in the request body. mTLS is widely used in service mesh architectures like Istio and Linkerd, zero-trust network designs, and B2B API integrations that require stronger authentication than API keys or OAuth tokens.

What this page covers

  • Server EKU TLS Web Server Authentication, OID 1.3.6.1.5.5.7.3.1
  • Client EKU TLS Web Client Authentication, OID 1.3.6.1.5.5.7.3.2
  • SPIFFE SVID a URI SAN of the form spiffe://trust-domain/path, typically 24-hour validity

Opens the X.509 Certificate Inspector with this section's checklist shown at the top of the tool.

Open in the tool →

mTLS certificate requirements versus server certificates

Client certificates for mTLS share the same X.509 structure as server certificates but differ in their Extended Key Usage extension. A server certificate includes the TLS Web Server Authentication OID (1.3.6.1.5.5.7.3.1) in its Extended Key Usage extension. A client certificate for mTLS includes the TLS Web Client Authentication OID (1.3.6.1.5.5.7.3.2)1.

The Subject distinguished name typically identifies the client rather than a domain name: for example, a client certificate for a microservice might have CN=payment-service, or a client certificate for a B2B partner might have O=Acme Corp, CN=partner-api. Furthermore, the CA that issues client certificates may be different from the CA that issues server certificates; many mTLS deployments use a private internal CA for client certificates while using a publicly trusted CA for server certificates. Inspecting a client certificate in the CapyToolkit Certificate Inspector confirms its Extended Key Usage OIDs, the Issuer, and the validity window, so you can verify the EKU before deployment.

How EKU OIDs decide which purpose a certificate can serve

Extended Key Usage is not a suggestion; it is a constraint that compliant TLS libraries enforce. Server-only certificates that lack the Client Authentication OID cannot be presented during a CertificateRequest without the peer rejecting them, and client-only certificates that lack the Server Authentication OID fail when accidentally configured on a web server. Software PKI tooling sometimes issues certificates with both OIDs to allow dual use, but that weakens the separation between client and server roles and makes a compromised client certificate usable for impersonating a server. When you generate a client certificate for mTLS, checking the EKU field before deployment catches misconfigured templates before they cause handshake failures in production.

A related check is to confirm the CA that issued the client certificate is the one the server actually trusts. mTLS fails in subtle ways when the client certificate chains to a different internal CA than the server's trust list expects, even when the certificate is otherwise valid. The CapyToolkit Certificate Inspector shows the Issuer and the chain for any client certificate, so you can compare it against the CA bundle the server is configured to verify before rolling out the connection.

Setting up and verifying mTLS in server configuration

Configuring mTLS on a server requires setting up client certificate verification against a specified CA trust list. In nginx, the ssl_client_certificate directive points to the CA certificate bundle that signed client certificates, and ssl_verify_client on enables verification2. In Node.js, the tls.createServer options object accepts ca (an array of CA certificates) and requestCert: true plus rejectUnauthorized: true3. The server uses the ssl_verify_depth or equivalent setting to limit the number of intermediates in the client certificate chain it will validate. Consequently, a misconfigured ssl_verify_depth that is too shallow causes valid client certificates signed through an intermediate to fail validation even when the chain is otherwise correct. The CapyToolkit Certificate Inspector can parse the client certificate to show its Issuer and Extended Key Usage OIDs, confirming the certificate carries the correct authentication purpose before configuring the server.

When ssl_verify_depth silently rejects valid client certificates

A deployment that switches from a direct CA issuance pattern to an intermediate CA often keeps the ssl_verify_depth setting at its default value of 1, which only validates client certificates signed directly by a trusted CA. Client certificates that chain through the new intermediate then fail validation even though every certificate in the chain is valid and signed correctly, because the verifier does not traverse deeply enough to reach a trusted root. The fix is to set ssl_verify_depth to at least 2 when an intermediate CA sits between the client certificate and the trust store, or higher when the chain has additional issuing layers. A quick way to detect this failure mode is to inspect the client certificate chain in the Certificate Inspector and count the intermediates between the leaf and the trusted root, then configure the depth to match.

mTLS in service mesh architectures and SPIFFE SVIDs

Service meshes like Istio and Linkerd use mTLS as the default authentication mechanism between services, issuing short-lived client and server certificates automatically via their control planes. Istio's istiod component issues SPIFFE-format X.509 SVIDs (SPIFFE Verifiable Identity Documents) to each workload, embedding the workload's identity as a URI SAN in the SPIFFE format: spiffe://cluster-id/ns/namespace/sa/service-account4. These certificates typically have 24-hour validity and rotate automatically. Consequently, mTLS in a service mesh eliminates the need to manage certificates manually for service-to-service communication, while still providing cryptographic proof of each service's identity. The CapyToolkit Certificate Inspector can parse SPIFFE certificates: paste the PEM and look for the URI SAN entry containing the SPIFFE ID in the Extensions section of the expanded card.

How short-lived SVIDs trade validity windows for revocation-free operation

Service meshes can afford one hour of validity because the control plane reissues certificates without operator intervention and workloads receive new credentials before the old ones expire. A shorter validity window limits the damage from a leaked private key, since a stolen certificate becomes useless within hours regardless of whether it has been revoked. Traditional revocation mechanisms like CRLs and OCSP introduce network latency and caching concerns that are unacceptable when every service connects to every other service dozens of times per second. By pairing short lifetimes with automated issuance, service meshes sidestep the revocation problem entirely while still maintaining strong cryptographic identity for every connection5.

When to use this

Use this guide when implementing service-to-service authentication in a microservices architecture, when setting up mTLS for a B2B API integration that requires stronger authentication than shared secrets, or when troubleshooting mTLS handshake failures. It also applies when designing the certificate issuance workflow for client certificates: unlike server certificates, client certificates for mTLS require a private CA or managed PKI service rather than a publicly trusted CA, and the Extended Key Usage extension must carry the Client Authentication OID. Furthermore, use this guide when migrating from API key authentication to mTLS, since the migration requires changes on both the server side and all clients before the cutover to avoid downtime. Building on this, apply the SPIFFE section whenever you are evaluating service mesh options, since understanding how Istio and Linkerd manage certificate lifecycles affects your choice of mesh and your observability requirements for certificate rotation events.

Examples

mTLS handshake failure: certificate required

The server requests a client certificate but the client is not configured to present one. Verify that the client TLS configuration includes the client certificate and private key files. In curl: add --cert client.pem --key client.key to the command.

mTLS failure: certificate verify failed — certificate not trusted

The server's client CA trust store does not include the CA that signed the client certificate. Add the client certificate's issuing CA to the server's ssl_client_certificate (nginx) or ca option (Node.js). Inspect the client certificate Issuer field in the Certificate Inspector to identify the correct CA to add.

Verifying SPIFFE certificate identity in a service mesh

Paste the workload certificate PEM into the Certificate Inspector. Look for a URI SAN entry in the Extensions section. A valid SPIFFE ID follows the format spiffe://trust-domain/path, for example spiffe://example.com/ns/default/sa/frontend.

Sources
  1. 1.

    Cooper, D., Santesson, S., Farrell, S., Boeyen, S., Housley, R., and Polk, W., "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile," RFC 5280, IETF, September 2008. https://www.rfc-editor.org/info/rfc5280

  2. 2.

    NGINX Project, "Module ngx_http_ssl_module," nginx.org, accessed June 2026. https://nginx.org/en/docs/http/ngx_http_ssl_module.html

  3. 3.

    Node.js Project, "TLS (SSL)," nodejs.org, accessed June 2026. https://nodejs.org/api/tls.html

  4. 4.

    SPIFFE Project, "X509-SVID," spiffe.io, accessed June 2026. https://spiffe.io/docs/latest/spiffe-specs/x509-svid/

  5. 5.

    Oracle, "Client-Driven OCSP and OCSP Stapling," docs.oracle.com, accessed September 2026. https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/ocsp.html

SSL Certificates for API Security

SSL certificates protect API endpoints the same way they protect web browser connections, but API security introduces additional certificate considerations beyond basic HTTPS. API consumers often enforce strict certificate validation, implement certificate pinning, or require mutual TLS where the client also presents a certificate. Unlike browser users who see a warning and can click through, API clients typically reject invalid certificates outright and throw errors that immediately surface in logs. Consequently, certificate problems on API endpoints cause immediate, visible failures that stop integration partners from making progress. This guide covers how to configure and verify certificates for API security, the specific fields API clients check, and when certificate pinning or mTLS authentication should supplement standard TLS for high-security API integrations.

What this page covers

  • Hostname coverage every hostname the client connects with must appear as a dNSName or iPAddress SAN
  • verify=False / -k / --insecure disables all TLS protection; a common development shortcut that leaks into production
  • Certificate pinning compares the live SHA-256 fingerprint against a stored expected value

Opens the X.509 Certificate Inspector with this section's checklist shown at the top of the tool.

Open in the tool →

Certificate validation in API clients

API clients, whether HTTP libraries, SDKs, or integration frameworks, perform the same chain validation as browsers but with stricter failure behavior and no user override option. Python's requests library validates certificates by default1; curl validates by default2; Java's HttpURLConnection validates by default3. When a certificate is expired, has a hostname mismatch, or presents an incomplete chain, these clients throw exceptions that immediately terminate the request rather than showing a warning. Yet the most dangerous API security pattern is disabling certificate validation entirely for debugging purposes and accidentally leaving it disabled in production code. The verify=False parameter in Python requests, the -k flag in curl, and ALLOW_ALL_HOSTNAME_VERIFIER patterns in Java all suppress TLS protection completely. Auditing API client code for these patterns is as important as auditing the certificates the server presents.

When verify=False becomes a production vulnerability

The quickest way to silence a certificate error during development is to disable verification entirely, and the most common mistake is leaving that shortcut in code that reaches production. Python's requests accepts verify=False, curl accepts -k and --insecure, and Java's SSLContext can be configured with a TrustManager that accepts every certificate without inspection. These bypasses remove every protection TLS provides, allowing man-in-the-middle interception of every request without either side noticing. Temporary exceptions for self-signed certificates during testing become permanent holes when environments are shared or configuration flags leak between deployments. For most teams, a safer approach is to add the specific CA to a custom trust bundle and keep verification enabled, preserving the same code path in development and production while still covering internal PKI that public roots do not trust.

Hostname validation and Subject Alternative Names for API endpoints

API endpoints often have hostnames that differ from web-facing domains: api.example.com, v2.api.example.com, or internal-api.example.com. Each hostname an API client uses to connect must appear in the server certificate's Subject Alternative Names extension. Consequently, a wildcard certificate for *.example.com covers api.example.com but not v2.api.example.com (two labels deep) or internal-api.internal.example.com4. Furthermore, API clients connecting to private or internal endpoints by IP address require the IP address to appear as an iPAddress SAN rather than a DNS SAN. Connecting by IP and having only a DNS SAN for the hostname causes hostname verification to fail. Inspect API certificates using the Certificate Inspector to verify that every hostname variant your client uses appears in the SAN extension before troubleshooting other potential causes.

Why hostnames and IP addresses need different SAN types

A common misconfiguration when securing internal APIs is issuing a certificate with only dNSName SAN entries while clients connect directly by IP. Hostname verification compares the connection target against the SAN values using rules defined in RFC 6125: a dNSName entry never matches an IPv4 or IPv6 address, so the only way to make an IP-based connection succeed is to include an iPAddress SAN entry for that exact IP. When the API is later load-balanced behind a different address, the certificate must be reissued because IP SANs are literal values, not patterns. For teams that prefer to avoid reissuing certificates on every infrastructure change, the more sustainable path is to assign the internal API a stable DNS name and use dNSName SANs that follow the service as it moves between clusters.

Certificate pinning for API security hardening

Certificate pinning supplements standard certificate validation by requiring the server to present a specific certificate or key, not just any certificate from a trusted CA5. An API client that pins a certificate fingerprint compares the SHA-256 fingerprint of the received certificate against a stored expected value and rejects any connection that does not match, even from a trusted CA. This defeats attacks where an attacker obtains a fraudulent certificate from a compromised CA, because the pinned fingerprint will not match the fraudulent certificate.

Why pinning operational discipline decides whether it helps or hurts

Yet pinning requires operational discipline: every time the server certificate renews, the pinned fingerprint must be updated in the client before the old certificate expires. Public-key pinning, which pins the fingerprint of the server's public key rather than the entire certificate, reduces this churn when the same key pair is reused across renewals. Teams that adopt pinning without a plan for updating clients before renewal deadlines introduce a new denial-of-service vector instead of closing an attack surface. The safest rollout pattern includes a fallback pin that is never used in production, allowing the new pin to be deployed and validated for a full rotation cycle before the old one is retired.

Deciding when pinning is worth the operational cost

Building on this, certificate pinning is most appropriate for high-security B2B API integrations where both sides control the client application and can coordinate certificate rotation in advance. Mobile applications that connect to a fixed backend, embedded devices managed through a single vendor, and partner APIs with a small number of known consumers all qualify as scenarios where the maintenance burden is justified by the reduction in acceptable CA risk. By contrast, public APIs with hundreds of independent clients experience pin Update failures too frequently to operate safely without an overwhelming support burden, and in those cases standard CA validation with monitoring provides better uptime at equivalent security.

For routine operations, the cheapest way to avoid pinning mistakes is to keep renewal and client updates on the same calendar. When the server certificate rotates, update the pinned fingerprint in the same change rather than as a separate follow-up that someone forgets. The CapyToolkit Certificate Inspector displays the SHA-256 fingerprint in the General section, so you can copy the exact fingerprint for pinning without recomputing it by hand.

When to use this

Use this guide when designing TLS configuration for a new API endpoint, when troubleshooting certificate validation failures from API clients, or when evaluating whether certificate pinning or mTLS is appropriate for a specific API security requirement. It also applies when reviewing API client code during a security audit: disabling certificate validation is a common development shortcut that persists into production code, and identifying those patterns requires knowing what to look for across each language and HTTP library. Furthermore, use this guide when onboarding an integration partner who will consume your API, since partners using strict validation or pinning need the certificate's SHA-256 fingerprint, the CA chain, and the renewal schedule in advance. Building on this, apply these checks whenever you add a new hostname or IP address to an existing API endpoint's certificate, since clients validating specific SAN entries will fail if the updated SAN list is not reflected in the deployed certificate.

Examples

API client reports SSL certificate verify failed: hostname mismatch

Inspect the server certificate SANs in the Certificate Inspector. Find the exact hostname the client uses to connect and verify it appears as a dNSName SAN entry. If it is not in the SANs, reissue the certificate with the correct names included.

Internal API served over an IP address failing TLS verification

An iPAddress SAN entry must match the IP address the client uses to connect. DNS SANs do not cover IP address connections. Reissue the certificate with the IP address in an iPAddress SAN field to resolve the verification failure.

Implementing certificate fingerprint pinning in a production API client

Retrieve the server certificate fingerprint from the Certificate Inspector's SHA-256 Fingerprint field. Store it in your client configuration as the expected value. Add code that compares the live certificate fingerprint against the stored value at connection time and rejects any mismatch.

Sources
  1. 1.

    Reitz, K. and contributors, "Advanced Usage — SSL Cert Verification," docs.python-requests.org, accessed June 2026. https://docs.python-requests.org/en/latest/user/advanced/#ssl-cert-verification

  2. 2.

    Stenberg, D. and contributors, "SSL Certificates," curl.se, accessed June 2026. https://curl.se/docs/sslcerts.html

  3. 3.

    Oracle, "HttpsURLConnection (Java Platform SE 8)," docs.oracle.com, accessed June 2026. https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/HttpsURLConnection.html

  4. 4.

    Saint-Andre, P. and Salz, R., "Service Identity in TLS," RFC 9525, IETF, January 2023. https://www.rfc-editor.org/info/rfc9525

  5. 5.

    OWASP Foundation, "Certificate and Public Key Pinning," owasp.org, accessed June 2026. https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning

FAQ

Use environment variables to control certificate validation. Set an environment variable like VERIFY_TLS=false in development configuration and VERIFY_TLS=true in production. Gate the verify=False parameter or -k flag on this variable. Code review your production configuration before deployment to ensure the development override is not present.

Certificate pinning stores the expected fingerprint of a specific certificate and rejects any certificate that does not match, even from trusted CAs. CA pinning stores the expected fingerprint of a specific CA certificate and accepts any leaf certificate signed by that CA, even if the leaf changes. CA pinning is easier to maintain across certificate renewals but still protects against other CAs.

Yes. API gateways like Kong, AWS API Gateway, and nginx Plus can terminate TLS from external clients and re-establish encrypted connections to backend services, handling certificate validation at the gateway level. Internal service-to-service connections may use mTLS for mutual authentication. The CapyToolkit Certificate Inspector parses each certificate in the chain separately, so you can verify the gateway presents the full correct chain to clients rather than relying on gateway logs alone. The gateway acts as a certificate trust boundary.

API clients with strict certificate validation refuse all connections to the endpoint from the moment the certificate expires. Unlike browser users who can choose to proceed, API clients throw exceptions and every API call fails until the certificate is replaced. The CapyToolkit Certificate Inspector shows the Not Before and Not After fields side by side, so you can confirm the expiry window and compare it against your deployment pipeline to confirm a renewal actually took effect. This failure causes immediate, measurable impact on dependent services.

Using separate certificates for the API and web application provides better isolation. If the API certificate's private key is compromised, the web application certificate is unaffected, and vice versa. Separate certificates also allow different renewal schedules and monitoring thresholds aligned with the security requirements of each endpoint.

FAQ

In standard TLS, only the server presents a certificate; the client verifies the server's identity but the server has no cryptographic proof of the client's identity. In mTLS, both sides present certificates. The server verifies the client certificate against its client CA trust store before accepting the connection, providing bidirectional cryptographic authentication.

mTLS can replace API keys as an authentication mechanism, providing stronger security because the client's identity is bound to a private key that never leaves the client. Unlike an API key, which is a shared secret that can be copy-pasted and shared, an mTLS client certificate's private key cannot be extracted from a properly configured HSM. The CapyToolkit Certificate Inspector displays the public key fingerprint and the full certificate chain, so you can confirm the client is presenting the expected credential before enabling mTLS on the server side.

After the server sends a CertificateRequest message, the client selects a certificate from its local store that satisfies the server's acceptable CA list and sends it in a Certificate message. The client then proves possession of the private key by sending a CertificateVerify message signed with the key. TLS libraries handle this automatically when configured with the client certificate and key files.

A SPIFFE SVID is an X.509 certificate with a SPIFFE URI in the Subject Alternative Names extension. The SPIFFE URI identifies the workload's identity in a standardized format: spiffe://trust-domain/path. Service meshes like Istio and Linkerd use SPIFFE SVIDs to provide unique, verifiable identities to each service instance without manual certificate management.

Service mesh environments typically use 24-hour validity with automatic rotation. For B2B integrations where certificate rotation requires coordination with partners, longer validity (90 days to one year) may be more practical. The shorter the validity, the smaller the compromise window if a client certificate's private key is stolen. The CapyToolkit Certificate Inspector shows the Not Before and Not After fields together, making it easy to verify that recently issued certificates use the intended validity window rather than inheriting a longer template by mistake. Balance security with operational complexity.