I seem to be having an issue with SSL whenever trying to use oAuth2 in Python. I\'ve spent most of the afternoon attempting to debug it but can\'t seem to figure it out.
I was having the same error on my system (OSX Yosemite) which had an old version of Python 2.7 installed (2.7.1).
I upgraded Python to 2.7.10 which solved the problem.
https://www.python.org/downloads/release/python-2710/
The clue was in the following warning message which I saw while I was experimenting with different solutions:
"InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning"
One more way to update your cacerts.txt
file is to keep httplib2
up to date. They occasionally update this file, so if you run into this problem, check if you're not using the latest version of the library and update it.
cacerts.txt
contains too few CAs. If you replace it with cacert.pem then there is no ssl error. Here's a test script:
#!/usr/bin/env python3
import http.client
import ssl
####context = ssl.create_default_context(cafile='cacerts.txt') # ssl.SSLError
####context = ssl.create_default_context(cafile='cacert.pem') # works
context = ssl.create_default_context() # works as is on the recent versions
#NOTE: ssl.CERT_REQUIRED is set for the default Purpose.SERVER_AUTH
h = http.client.HTTPSConnection('api.instagram.com', 443, context=context)
h.request('POST', '/oauth/access_token')
resp = h.getresponse()
print(resp.status, resp.reason) # produce expected 400 http error
print(resp.headers)
print(resp.read())
As the example demonstrates, the default CA list might be enough on the recent software versions.
The default cacerts.txt that comes with httplib2 contains these certificates:
The instagram HTTPS certificate is signed by:
You will need to add the certificate to your cacerts.txt
First, run pip install certifi
. Then set the client's ca_certs property, before making any requests:
client = oauth.Client(consumer)
client.ca_certs = certifi.where()
This was inspired by jterrace's suggestion to use httplib2.Http.add_certificate
I was running into the same issue with Flask-Social's OAuth call to Facebook. The easiest solution is to install httplib2.ca_certs_locator plug-in.
In httplib2.init.py, there is a check built-in for loading certificates from another source instead of the cacerts.txt file provided with the library:
try:
# Users can optionally provide a module that tells us where the CA_CERTS
# are located.
import ca_certs_locater
CA_CERTS = ca_certs_locater.get()
except ImportError:
# Default CA certificates file bundled with httplib2.
CA_CERTS = os.path.join(
os.path.dirname(os.path.abspath(__file__ )), "cacerts.txt")
Installing this plug-in fixed the problem for me with no code-changes/hack-a-rounds.