techdisrupt techdisrupt - 3 months ago 24
Python Question

Performing POST on a URL string in Django

I'm using the LinkedIn Authentication at: http://developer.linkedin.com/documents/authentication and I need to make a post. I'm familiar with making a GET request for example as:

client = oauth.Client(consumer, access_token)
resp,content = client.request("http://api.linkedin.com/v1/people/~?format=json", "GET", "")


Which used Oauth authentication. However for the Post part of the authentication, I have to POST an example string such as:

https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code
&code=AUTHORIZATION_CODE
&redirect_uri=YOUR_REDIRECT_URI
&client_id=YOUR_API_KEY
&client_secret=YOUR_SECRET_KEY


and my simple question relates to understanding what the best way to do this is - without using the Oauth (assuming that is the correct approach), since I have returned the AUTHORIZATION_CODE. Apologies if this is a simple question.

So in other words, I have a string of the above form, now, How do I perform a post?

I've tried using cURL. But I find the code fails at the post line:
c.perform()
. Here is the code I am using:

accesscode = request.GET.get('code')
redirect_uri = 'http://www.example.com'
url_post = 'https://www.linkedin.com/uas/oauth2/accessToken'
postdata = urllib2.quote('grant_type=authorization_code&code='+accesscode+'&redirect_uri='+redirect_uri+'&client_id='+consumer_key+'&client_secret='+consumer_secret)
#return HttpResponse(postdata)

c = pycurl.Curl()
c.setopt(c.URL, url_post)
c.setopt(c.POSTFIELDS, postdata)
c.setopt(c.VERBOSE, True)
c.setopt(c.FAILONERROR, True)
c.perform()


I'm getting the following error:

error at /loginsuccess/
(22, 'The requested URL returned error: 400 Bad Request')


Here is the code for how I am obtaining the first stage of the Authentication (as is suggested by the LI documentation):

def login(request):
redirect_uri = urllib2.quote('http://127.0.0.1:8080/loginsuccess')
codeURL = "https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=c3skrqz5wqmm&scope=r_fullprofile&state=DCEEFWF45453sdffef425&redirect_uri=" + redirect_uri
return HttpResponseRedirect(codeURL)


Here is the latest traceback that I am getting after using the code suggested below to post the data. I have a number of questions that I will outline after the trace.

Error:

HTTPConnectionPool(host='127.0.0.1', port=8888): Max retries exceeded with url: https://api.linkedin.com/uas/oauth/accessToken (Caused by : [Errno 111] Connection refused)

Environment:

Request Method: GET
Request URL: http://127.0.0.1:9000/loginsuccess/?code=AQQKMnhjMNKFEu08DkftejkNLQgSz-mIsMZtE36rGxrLfycx331iLXeC3LdAq63OTQeATAEXrA7FxgHSJWVHyh_iWyIEzVR6jp4zJsz41tpRipS14RE&state=DCEEFWF45453sdffef425

Django Version: 1.4.5
Python Version: 2.7.4
Installed Applications:
('django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware')


Traceback:
File "/usr/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs)
File "/home/brett/LinkedIn/brett/brett/views.py" in loginsuccess
68. r = requests.post(access_token_url, data=postdata)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py" in post
88. return request('post', url, data=data, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py" in request
44. return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py" in request
335. resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py" in send
438. r = adapter.send(request, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py" in send
327. raise ConnectionError(e)

Exception Type: ConnectionError at /loginsuccess/
Exception Value: HTTPConnectionPool(host='127.0.0.1', port=8888): Max retries exceeded with url: https://api.linkedin.com/uas/oauth/accessToken (Caused by <class 'socket.error'>: [Errno 111] Connection refused)


Plus with the request information there is still no POST data it would seem:

Request information

GET
Variable Value
state

u'XX'
code

u'XX'
POST
No POST data
FILES
No FILES data

Here is more details.

Request Method: GET
Request URL: http://127.0.0.1:9000/loginsuccess/?code=XXX&state=XXX
Django Version: 1.4.5
Exception Type: ConnectionError
Exception Value:
HTTPConnectionPool(host='127.0.0.1', port=8888): Max retries exceeded with url: https://api.linkedin.com/uas/oauth/accessToken (Caused by <class 'socket.error'>: [Errno 111] Connection refused)
Exception Location: /usr/local/lib/python2.7/dist-packages/requests/adapters.py in send, line 327
Python Executable: /usr/bin/python





Fiddler results:

HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
P3P: CP="CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE"
X-LI-UUID: dI14TYAfd/RHJ8mVmAN8Gg==
Location: http://127.0.0.1:9000/loginsuccess?code=XX=XX
Content-Language: en-US
Content-Encoding: gzip
Vary: Accept-Encoding
Date: Thu, 05 Sep 2013 19:26:48 GMT
X-Li-Fabric: PROD-ELA4
Set-Cookie: _lipt=deleteMe; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/
Set-Cookie: leo_auth_token="XX"; Version=1; Max-Age=1799; Expires=Thu, 05-Sep-2013 19:56:47 GMT; Path=/
Set-Cookie: sl="delete me"; Version=1; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/
Set-Cookie: sl="delete me"; Version=1; Domain=.www.linkedin.com; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/
Set-Cookie: lang="v=2&lang=en-us"; Version=1; Domain=linkedin.com; Path=/
Pragma: no-cache
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-Control: no-cache, no-store
Age: 1
Transfer-Encoding: chunked
Connection: keep-alive
X-Li-Pop: PROD-IDB2

14
�����������������
0

Answer

Take a look at requests (install with pip install requests), you can make the POST request easily with just some lines of code:

import requests

accesscode = request.GET.get('code')
redirect_uri = 'http://www.example.com'
url = 'https://www.linkedin.com/uas/oauth2/accessToken'
# ... your code ...

postdata = {
    'grant_type': 'authorization_code',
    'code': accesscode,
    'redirect_uri': redirect_uri,
    'client_id': consumer_key,
    'client_secret': consumer_secret,
}

r = requests.post(url, data=postdata)
print r.status_code
print r.text

You can try this in Python shell since I think it's simple enough to do so.