certificate verify failed: unable to get local issuer certificate certificate verify failed: unable to get local issuer certificate python python

certificate verify failed: unable to get local issuer certificate


For anyone who still wonders on how to fix this, i got mine by installing the "Install Certificates.command"

Here is how I did,

Install Certificates.commad location

Just double click on that file wait for it to install and in my case, you will be ready to go


I hit the same issue on OSX, while my code was totally fine on Linux, and you gave the answer in your question!

After inspecting the file you pointed to /Applications/Python 3.7/Install Certificates.command, it turned out that what this command replaces the root certificates of the default Python installation with the ones shipped through the certifi package.

certifi is a set of root certificates. Each SSL certificate relies a chain of trust: you trust one specific certificate because you trust the parent of that certificate, for which you trust the parent, etc. At some point, there is no "parent" and those are "root" certificates. For those, there is no other solution than bundling commonly trusted root certificates (usually big trust companies like eg. "DigiCert").

You can for instance see the root certificates in your browser security settings (for instance for Firefox->Preference->Privacy and security->view certificates->Authorities).

Coming back to the initial problem, and prior to running the .command file, executing this returns for me an empty list on a clean installation:

import osimport ssl                                        openssl_dir, openssl_cafile = os.path.split(          ssl.get_default_verify_paths().openssl_cafile)# no content in this folderos.listdir(openssl_dir)# non existent fileprint(os.path.exists(os.path.join(openssl_dir, openssl_cafile)))

This means that there is no default certificate authority for the Python installation on OSX. A possible default is exactly the one provided by the certifi package.

After that, you just can create an SSL context that has the proper default as the following (certifi.where() gives the location of a certificate authority):

import platform# ...ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS)ssl_context.verify_mode = ssl.CERT_REQUIREDssl_context.check_hostname = Truessl_context.load_default_certs()if platform.system().lower() == 'darwin':    import certifi    ssl_context.load_verify_locations(        cafile=os.path.relpath(certifi.where()),        capath=None,        cadata=None)

and make request to an url from python like this:

import urllib# previous contexthttps_handler = urllib.request.HTTPSHandler(context=ssl_context)opener = urllib.request.build_opener(https_handler)ret = opener.open(url, timeout=2)


This worked in all OS:

import sslimport certifiurlopen(request, context=ssl.create_default_context(cafile=certifi.where()))