Servers and proxies

Client auth EKU removed: mTLS fails with public certificates

By · Last verified

Error messageclient SSL certificate verify error: (26:unsupported certificate purpose)

This error means a server that requires a client certificate received a certificate whose Extended Key Usage allows only server authentication. Since 2026 public CAs such as Let's Encrypt no longer put the TLS Client Authentication EKU into TLS certificates, so any mutual TLS setup that used a public certificate on the client side fails after renewal.

Quick fix

A client certificate that lists only TLS Web Server Authentication confirms the problem.

Check the EKU of the certificate the client presents, with the command below or the certificate decoder:

openssl x509 -in client.pem -noout -ext extendedKeyUsage

If the output shows only TLS Web Server Authentication, the missing clientAuth EKU is your problem. Issue a client certificate from a private CA instead and configure the server to trust that CA:

# one-time: create a private CA (keep ca.key offline or in an HSM/KMS)
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes \
  -keyout ca.key -out ca.pem -days 3650 -subj "/CN=Example Internal Client CA"

# per client: key, CSR, and a certificate with clientAuth
openssl req -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes \
  -keyout client.key -out client.csr -subj "/CN=billing-service"
printf "extendedKeyUsage=clientAuth\nkeyUsage=digitalSignature\n" > client.ext
openssl x509 -req -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial \
  -out client.pem -days 90 -extfile client.ext
ssl_client_certificate /etc/nginx/client-ca.pem;   # private CA only
ssl_verify_client on;

Causes

1. Your public certificate lost clientAuth at renewal

Most cases start at renewal: the new public certificate no longer includes clientAuth.

  • What changed: the Chrome Root Program Policy (v1.8) makes public CAs split server and client authentication into separate hierarchies. Subordinate CA certificates disclosed to CCADB on or after 15 June 2026 must carry only the serverAuth EKU, and subscriber certificates issued on or after 15 March 2027 must include an EKU that asserts only serverAuth. CAs removed clientAuth earlier on their own schedules: Let's Encrypt removed clientAuth from its default classic profile on 11 February 2026, kept an opt-in tlsclient profile until 8 July 2026, and its new Generation Y certificates carry server authentication only.
  • Confirm: the failing certificate is from a public CA, was issued recently, and the EKU check above shows only server authentication.
  • Fix: move the client side to a private CA as shown above.

2. Server-to-server mutual authentication

Some setups reuse the same certificate in both directions: a service presents its web certificate when it calls another service, an XMPP or mail server presents its server certificate on outgoing connections, or replication peers authenticate each other with public certificates.

  • Confirm: the error appears in the logs of the receiving server, and the sending server uses its normal public certificate as its client identity.
  • Fix: give each peer a second certificate from a private CA for the client role, or switch that link to a different authentication method (shared secret, OAuth 2.0 client credentials, signed tokens) if the protocol allows it.

3. The private CA certificate lacks the right EKU

If you already use a private CA and still see error 26, the client certificate or an intermediate CA was issued without clientAuth.

  • Confirm: run the EKU check on the leaf and on each intermediate; an intermediate with an EKU extension must also include clientAuth.
  • Fix: reissue with extendedKeyUsage=clientAuth.

Fixes by environment

On every server, issue client certificates from your own private CA and trust only that CA for client authentication.

Nginx: set ssl_verify_client on and point ssl_client_certificate at the private CA bundle only. Remove public roots from that file.

Apache httpd: set SSLVerifyClient require and SSLCACertificateFile /etc/httpd/client-ca.pem.

Java clients: load the private client key pair into a PKCS#12 keystore (-Djavax.net.ssl.keyStore=client.p12). A serverAuth-only certificate is rejected with a message such as "Extended key usage does not permit use for TLS client authentication".

Go: a server using tls.RequireAndVerifyClientCert rejects the certificate with x509: certificate specifies an incompatible key usage. Set ClientCAs to a pool containing only the private CA.

Kubernetes and service meshes: use cert-manager with a CA or Vault issuer for workload certificates; meshes such as Istio and Linkerd already issue mTLS certificates from their own private CA.

Private CA software: options include smallstep step-ca, HashiCorp Vault PKI, cloud private CA services and, for small setups, plain OpenSSL. Automate issuance and renewal the same way you automate public certificates.

Don't do this

  • Disable the purpose check (for example by forcing OpenSSL's purpose to "any" or patching the verifier). The server would then accept certificates that were never meant to identify clients.
  • Set ssl_verify_client optional_no_ca to make the error disappear. Nginx then accepts any client certificate without verifying who issued it, which removes the authentication you wanted.
  • Trust a public root store for client certificates. Any certificate holder of that CA could authenticate. Keep the client trust anchor private.
  • Look for a CA that still mixes server and client EKUs to keep the old setup. Even if one exists today, Chrome Root Program Policy requires subscriber certificates issued from 15 March 2027 to assert only serverAuth, so the option has a fixed end date.

FAQ

My website certificate from Let's Encrypt is fine. Am I affected?

No. Browsers and normal HTTPS clients only check the TLS Server Authentication EKU, which is still present. You are affected only if some system presents your public certificate as a client certificate, for example to another server that requires mutual TLS.

Can I still get a public certificate with clientAuth?

Not from Let's Encrypt: the tlsclient profile stopped on 8 July 2026. Other public CAs have been dropping clientAuth on their own schedules, and under the Chrome Root Program Policy every subscriber certificate issued on or after 15 March 2027 must assert only serverAuth, so any remaining option ends by then at the latest. The durable answer is a private CA.

Why did things keep working for a while after the change?

Certificates issued before the change keep their EKUs until they expire. A Let's Encrypt certificate is valid for 90 days by default, so the failure appeared at the first renewal that produced a serverAuth-only certificate. As of November 2026 every Let's Encrypt certificate with clientAuth has expired.

Is using a public CA for client authentication a bad idea anyway?

Usually yes. If a server trusts a public root for client certificates, anyone who can get a certificate for any domain from that CA can present a valid client certificate. A private CA lets you decide exactly who receives client certificates and revoke them yourself.

Sources

  1. Let's Encrypt: Ending TLS Client Authentication Certificate Support in 2026
  2. Let's Encrypt: Profiles
  3. Chrome Root Program Policy
  4. OpenSSL X509_STORE_CTX_get_error (verification error codes)
  5. nginx ngx_http_ssl_module