How Guzzle validates SSL certificates when making outbound API requests
Here are the most common Certificate Authorities (CAs) you'll encounter:
Major Commercial CAs
CA | Known For |
|---|---|
DigiCert | Enterprise, acquired Symantec/Verisign's SSL business |
Sectigo (formerly Comodo) | High volume, affordable certs |
GlobalSign | Popular in enterprise and IoT |
Entrust | Government and financial sector |
GoDaddy | Popular with small/medium sites |
IdenTrust | Issues intermediate certs to other CAs |
Free / Automated CAs
CA | Known For |
|---|---|
Let's Encrypt | Free, automated, widely adopted — backed by Mozilla, EFF, Cisco |
ZeroSSL | Free alternative to Let's Encrypt |
Buypass | Free tier available, Norway-based |
Government / Specialized CAs
CA | Known For |
|---|---|
ISRG | The nonprofit behind Let's Encrypt |
Actalis | European/Italian government use |
SwissSign | Swiss federal government |
In Practice
- Most SaaS APIs (like Constant Contact, Stripe, Twilio) use DigiCert or Sectigo
- Most modern websites are moving toward Let's Encrypt for automatic renewal
- IdenTrust is notable because it cross-signed Let's Encrypt's root early on, which is why LE certs were trusted so broadly from the start
All of these are pre-included in Ubuntu's ca-certificates package
Sometime we need to understand how PHP's HTTP client validates SSL certificates when making outbound API requests.
Here's how it works:
How SSL Trust Works in PHP API Calls
When your Drupal app calls the Constant Contact API, the trust chain works like this:
1. The OS/Server Certificate Bundle PHP (via cURL under the hood) uses a CA certificate bundle — typically the system's trusted CA store or a bundled cacert.pem file. Constant Contact's cert is signed by a trusted CA (like DigiCert), which is already in that bundle, so it's trusted automatically.
2. How Drupal or your phpapp handles it. Guzzle (or a similar HTTP client) delegates the request to PHP's cURL extension. The relevant settings are:
CURLOPT_SSL_VERIFYPEER => true // verifies the cert chain CURLOPT_SSL_VERIFYHOST => 2 // verifies the hostname matches CURLOPT_CAINFO => '/path/to/cacert.pem' // the CA bundle to trustWhere the CA Bundle Comes From
Source | Location |
|---|---|
Linux system store |
|
PHP's bundled certs | Compiled in, or set via |
Guzzle's bundle | Pulled from |
You can check what your PHP install is using:
var_dump(openssl_get_cert_locations()); // or echo ini_get('curl.cainfo');Common Issues & Fixes
SSL verification failing in dev/local? Check your CA bundle is up to date:
# On Ubuntu/Debian sudo apt-get update && sudo apt-get install ca-certificates
# Or point PHP to Mozilla's bundle via Composer composer require guzzlehttp/guzzle # ships its own cacert.pemManually specifying the CA bundle in php.ini:
curl.cainfo = "/etc/ssl/certs/ca-certificates.crt" openssl.cafile = "/etc/ssl/certs/ca-certificates.crt"
If you need to pass custom Guzzle options (e.g. a specific CA file), look for where the library instantiates its Guzzle client and pass:
$client = new \GuzzleHttp\Client([ 'verify' => '/path/to/cacert.pem', // or false to disable (dev only!) ]);The Short Answer
Find out what vendor the third party API service uses. You can then check that it exists in the system ca store.
# Check if [vendor] certs are present in the system store
grep -r "[third party vendor]" /etc/ssl/certs/ # Or list all trusted CAs awk -v cmd='openssl x509 -noout -subject' '/BEGIN/{close(cmd)}; {print | cmd}' \ < /etc/ssl/certs/ca-certificates.crt | grep -i [third party vendor]
Your server trusts [Third Party]'s SSL cert because [ThirdParty]'s SSL cert Vendor (their CA) is already in your system/PHP trust store — no special configuration needed in normal production environments. Issues usually only arise when the CA bundle is outdated or missing in containerized/minimal server environments.
Recent content
-
2 hours 17 minutes ago
-
3 days 11 hours ago
-
1 week ago
-
1 week 2 days ago
-
1 week 2 days ago
-
1 week 2 days ago
-
1 week 2 days ago
-
2 weeks 3 days ago
-
2 weeks 6 days ago
-
1 month ago