OAuth Echo problem in python

53 views
Skip to first unread message

yml

unread,
Jun 3, 2010, 11:20:42 AM6/3/10
to Twitter Development Talk, nic...@lincolnloop.com
Hello,
I am in the process of writing a python web app that should enable the
user to post picture to twitpic using the Oauth Echo authorization
mechanism.

The application is already able to post tweet using the Oauth
authentication so the access_token is available to us in the session.

So my question to you guys is that it would be great if someone could
point what is the issue in the code below or paste some sample code
that upload a picture in python to twitpic.



""""
# OauthRequest is from the python-oauth lib
# I overide the to_header method to return a dict with the right key.

class TwitpicOAuthRequest(OAuthRequest):
def to_header(self, realm='http://api.twitter.com/'):
headers = super(TwitpicOAuthRequest,
self).to_header(realm=realm)
return {'X-Verify-Credentials-Authorization':
headers['Authorization']}

def post_photo(request):
if request.method == 'POST':
form = PhotoForm(request.POST, request.FILES)
if not request.session.get('twitter_access_token'):
return HttpResponse("Not authenticated")
if form.is_valid():
access_token = request.session['twitter_access_token']

params = {
'oauth_consumer_key': settings.TWITTER_CONSUMER_KEY,
'oauth_signature_method':"HMAC-SHA1",
'oauth_token':access_token.key,
'oauth_timestamp':oauth.generate_timestamp(),
'oauth_nonce':oauth.generate_nonce(),
'oauth_version':'1.0'
}

consumer =
oauth.OAuthConsumer(key=settings.TWITTER_CONSUMER_KEY,

secret=settings.TWITTER_CONSUMER_SECRET)
token = oauth.OAuthToken(key=access_token.key,
secret=access_token.secret)
oauth_request = TwitpicOAuthRequest(http_method="POST",

http_url=settings.TWITPIC_API_URL,
parameters=params)

signature=oauth_request.build_signature(OAuthSignatureMethod_HMAC_SHA1(),
consumer,
access_token)

headers = oauth_request.to_header()
headers['X-Auth-Service-Provider'] = 'https://
api.twitter.com/1/account/verify_credentials.json'
headers['X-Verify-Credentials-Authorization'] += ',
oauth_signature="%s"' %signature

values = {}
values['key'] = settings.TWITPIC_API_KEY
values['message'] = form.cleaned_data['message']
# the path to the file is hardcoded here in the future it
will be taken from the from
values['media'] = open("/home/yml/Desktop/copine_moi.jpg",
"rb")
register_openers()
datagen, heads = multipart_encode(values)
headers.update(heads)

req = urllib2.Request(settings.TWITPIC_API_URL, datagen,
headers)
response = urllib2.urlopen(req)

return HttpResponse("the photo is posted")
else:
form = PhotoForm(initial={"created_at":datetime.now()})

return render_to_response("twitter_integration/photo_form.html",
{"form":form,},

context_instance=RequestContext(request))
""""

yml

unread,
Jun 3, 2010, 2:38:40 PM6/3/10
to Twitter Development Talk
I would greatly appreciate any help.
Here it is the latest evolution of this piece of code :
oauth_request = TwitpicOAuthRequest(http_method="GET",

#http_url=settings.TWITPIC_API_URL,

http_url=settings.TWITTER_VERIFY_CREDENTIALS,
parameters=params)

signature=oauth_request.sign_request(OAuthSignatureMethod_HMAC_SHA1(),
consumer,
access_token)

headers = oauth_request.to_header()
headers['X-Auth-Service-Provider'] =
settings.TWITTER_VERIFY_CREDENTIALS


#with multipart_encode
values = [
MultipartParam('key',value=settings.TWITPIC_API_KEY),

MultipartParam('message',value=form.cleaned_data['message']),
MultipartParam('media',
filename='copine_moi.jpg',
filetype='image/jpeg',
fileobj=open("/home/yml/Desktop/
copine_moi.jpg","rb"))
]

register_openers()
datagen, heads = multipart_encode(values)
headers.update(heads)
req = urllib2.Request(settings.TWITPIC_API_URL, datagen,
headers)
# Post to netcat -l -p 9000
#req = urllib2.Request("http://127.0.0.1:9000", datagen,
headers)

#with urlencode
#values = {}
#values['key'] = MultipartParam(settings.TWITPIC_API_KEY)
#values['message'] =
MultipartParam(form.cleaned_data['message'])
#values['media'] = open("/home/yml/Desktop/
copine_moi.jpg", "rb").read()
#data = urllib.urlencode(values)
#req = urllib2.Request(settings.TWITPIC_API_URL, data,

Steve C

unread,
Jun 3, 2010, 6:15:25 PM6/3/10
to Twitter Development Talk
I just looked at your code briefly, but I believe the problem is this
line:

oauth_request = TwitpicOAuthRequest(http_method="POST",
http_url=settings.TWITPIC_API_URL,

The OAuth Request needs to be signed using the Twitter Endpoint
(https://api.twitter.com/1/account/verify_credentials.json), not the
Twitpic API URL.

Try something like this:

oauth_request = TwitpicOAuthRequest(http_method="GET",
http_url="https://api.twitter.com/1/account/verify_credentials.json",

Yann Malet

unread,
Jun 3, 2010, 6:49:19 PM6/3/10
to twitter-deve...@googlegroups.com
Thanks Steve for your reply but has you could see in the second code snippet I have posted i have changed this from POST to GET without much success.

I had also replaced the http_url has you suggest.

One of my question is how does the file should be sent in the  ? multipart_encode or urlencode

I would be glad to provide you with any additional information if you need it.
Regards,
--yml

Zac Bowling

unread,
Jun 3, 2010, 7:41:05 PM6/3/10
to twitter-deve...@googlegroups.com
It may not help fix your problem but I would recommend upgrading to the python-oauth2 library. (Don't be confused by the name; it's not an oauth 2.0 library, but just the next generation of the original oauth 1.0a library that Leah Culver wrote). There are bunch of little issues with the original one that don't follow the spec exactly that are fixed and it's not a difficult upgrade (as long as your are not hosting an OAuth server of your own because those interfaces changed considerably).

http://github.com/zbowling/python-oauth2 (the fork I maintain with bunch of twitter related fixes and workarounds)
or:
http://github.com/simplegeo/python-oauth2 (the official upstream)

Zac Bowling
@zbowling

Yann Malet

unread,
Jun 3, 2010, 9:37:26 PM6/3/10
to twitter-deve...@googlegroups.com
Zac,
I would love to do this but I can't find any documentation on how to do Oauth Echo with python-oauth2. I would gladly switch to python-ouath2 if I could find some code showing How to use it to post a picture on twitpic : http://dev.twitpic.com/docs/2/upload/

Any help would be greatly appreciated.
Regards,
--yml

Zac Bowling

unread,
Jun 3, 2010, 10:48:58 PM6/3/10
to twitter-deve...@googlegroups.com
Hi Yann,

I don't see anything obvious that stands out as wrong to me in your implementation from just looking at it, but I'm not sure. I do have OAuth Echo code working for Twitpic but using the OAuth2 library. If you don't figure out an answer, you can hit me up off the list and I'll see if I separate our version so it works independently and I'll post it on gist for you. 

If you want to upgrade though to python-oauth2, the biggest change is swapping out your imports to use oauth2 instead of oauth and removing the "OAuth" prefix on all the class names.

For example:
  import oauth
  oauth.OAuthRequest(...)
  oauth.OAuthToken(...)

becomes: 
  import oauth2
  oauth2.Request(...)
  oauth2.Token(...)

etc...

Most of the API that you care about is identical from there. The library has evolved a bit but it should be obvious and most of the public methods remained the same. In my fork, I've fixed a few issues and added some changes to support XAuth and a few other minor issues (like forcing Authentication headers on POSTs for Twitter). 

Zac Bowling
@zbowling

noki

unread,
Jun 4, 2010, 3:13:40 AM6/4/10
to Twitter Development Talk
Hi,

I also stacked on the TwitPic's OAuth Echo Protocol a week ago.

The point was making header just like to request Twitter.
1. make OAuth Header to request Account/Verify_credentials to get JSON
not XML as result by GET method.
2. insert this header into X-Verify-Credentials-Authorization header
with realm.

You make verification request header, and TwitPic send it to Twitter
as you send in TwitPic site. Remember the OAuth Echo was just an echo
protocol.

The image file to send to TwitPic should be included as multipart/form-
data format.

I wrote a blog article for Ruby language and hope the code in the
article make some help.
--
Norio Suzuki

noki

unread,
Jun 4, 2010, 3:29:46 AM6/4/10
to Twitter Development Talk
Ah, I forgot to include my blog URL.

http://postcard.blog.ocn.ne.jp/itazura/2010/05/twitpic_api_v2_.html

This was written in Japanese but you will find code to upload.

Yann Malet

unread,
Jun 4, 2010, 9:14:06 AM6/4/10
to twitter-deve...@googlegroups.com
Hello Zac,

I rewrote everything in my app based on python-oauth2 : http://dpaste.com/203168/
The file is still hardcoded to ease the comprehension. I hope this will help you to spot my issue.

The error message I get from twitpic is 400 bad request.
Regards,
--yml


"""
class OAuthEchoRequest(oauth.Request):
    def to_header(self, realm='http://api.twitter.com/'):
        headers = super(OAuthEchoRequest, self).to_header(realm=realm)
        return {'X-Verify-Credentials-Authorization': headers['Authorization']}

@login_required
def twitpic_upload_photo(request):
    if request.method == 'POST':
        form = PhotoForm(request.POST, request.FILES)
        if form.is_valid():
            profile = Profile.objects.get(user=request.user)
            token = oauth.Token(profile.oauth_token,
                               profile.oauth_secret)

            params = {
                'oauth_consumer_key': settings.TWITTER_CONSUMER_KEY,
                'oauth_signature_method':"HMAC-SHA1",
                'oauth_token':token.key,
                'oauth_timestamp':oauth.generate_timestamp(),
                'oauth_nonce':oauth.generate_nonce(),
                'oauth_version':'1.0'
            }

            oauth_echo_request = OAuthEchoRequest(method="GET",
                                          url=settings.TWITTER_VERIFY_CREDENTIALS,
                                          #parameters=params
                                          )
            signature=oauth_echo_request.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer, 
                                    token)
            
            headers = oauth_echo_request.to_header()
            headers['X-Auth-Service-Provider'] = settings.TWITTER_VERIFY_CREDENTIALS

            
            #with multipart_encode
            values = [
                MultipartParam('key',value=settings.TWITPIC_API_KEY),
                MultipartParam('message',value=form.cleaned_data['message']),
                MultipartParam('media',
                               filename='copine_moi.jpg',
                               filetype='image/jpeg',
                               fileobj=open("/home/yml/Desktop/copine_moi.jpg","rb"))
            ]
           
            register_openers()
            datagen, heads = multipart_encode(values)
            headers.update(heads)
            req = urllib2.Request(settings.TWITPIC_API_URL, datagen, headers)
            # Post to netcat 
            #req = urllib2.Request("http://127.0.0.1:9000", datagen, headers)
            
            #with urlencode
            #values = {}
            #values['key'] = MultipartParam(settings.TWITPIC_API_KEY)
            #values['message'] = MultipartParam(form.cleaned_data['message'])
            #values['media'] = open("/home/yml/Desktop/copine_moi.jpg", "rb").read()
            #data = urllib.urlencode(values)
            #req = urllib2.Request(settings.TWITPIC_API_URL, data, headers)

            
            response = urllib2.urlopen(req)

            return HttpResponse("the photo is posted")
    else:
        form = PhotoForm()
        
    return direct_to_template(request,
                              "twitter_integration/photo_form.html",
                              {"form":form,})

Yann Malet

unread,
Jun 4, 2010, 9:20:49 AM6/4/10
to twitter-deve...@googlegroups.com
If I send this request to 127.0.0.1:9000 without the file here it is the string I can observe : 

"""
(ve)yml@yml-laptop:jess3$ netcat -l -p 9000
POST / HTTP/1.1
Accept-Encoding: identity
Content-Length: 377
User-Agent: Python-urllib/2.6
Connection: close
Content-Type: multipart/form-data; boundary=a45bd25da2844dac81003987b3c19e18
X-Verify-Credentials-Authorization: OAuth realm="http://api.twitter.com/", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="y2hEqGNEmyjU2De3hNcg", oauth_token="90476798-5VZeNLpXUCaJ06UaWve2c4JVfdcJj5D4r21JxUFM", oauth_signature="NMPlU4cRYl0b6jbQJ1xGXaZ5%2FpM%3D"

--a45bd25da2844dac81003987b3c19e18
Content-Disposition: form-data; name="key"
Content-Type: text/plain; charset=utf-8
Content-Length: 32

4bb040d1ec65427f8038cdd60a12cde2
--a45bd25da2844dac81003987b3c19e18
Content-Disposition: form-data; name="message"
Content-Type: text/plain; charset=utf-8
Content-Length: 13

copine et moi
--a45bd25da2844dac81003987b3c19e18--
^C
(ve)yml@yml-laptop:jess3$ 

"""

Does any one can spot the issue ?
Regards,
--yml

Steve C

unread,
Jun 4, 2010, 9:38:58 AM6/4/10
to Twitter Development Talk
Twitpic will only 400 Bad Request you if it can't find the image in
your multipart/form-
data or if the image is invalid (not jpg/png/gif or >5MB in size).

Thanks,

Steve C
Twitpic
> >> On Thu, Jun 3, 2010 at 7:41 PM, Zac Bowling <zbowl...@gmail.com> wrote:
>
> >>> It may not help fix your problem but I would recommend upgrading to the
> >>> python-oauth2 library. (Don't be confused by the name; it's not an oauth 2.0
> >>> library, but just the next generation of the original oauth 1.0a library
> >>> that Leah Culver wrote). There are bunch of little issues with the original
> >>> one that don't follow the spec exactly that are fixed and it's not a
> >>> difficult upgrade (as long as your are not hosting an OAuth server of your
> >>> own because those interfaces changed considerably).
>
> >>>http://github.com/zbowling/python-oauth2(the fork I maintain with bunch
> >>> of twitter related fixes and workarounds)
> >>> or:
> >>>http://github.com/simplegeo/python-oauth2(the official upstream)
> >>> >>                 MultipartParam('key',value=settings.TWITPIC_API_KEY),...
>
> read more »

Yann Malet

unread,
Jun 4, 2010, 9:56:26 AM6/4/10
to twitter-deve...@googlegroups.com
Steve,
The image is only 33.7kb and it is  a jpg.
Do you have any python sample code for the ?
Regards,
--yml

Yann Malet

unread,
Jun 4, 2010, 9:59:08 AM6/4/10
to twitter-deve...@googlegroups.com
I have just uploaded the same image using the web interface : http://twitpic.com/1ttrlu
do you have any recommendation ? On how to solve this issue.
Regards,
--yml

yml

unread,
Jun 4, 2010, 3:48:59 PM6/4/10
to Twitter Development Talk
At that point both services yfrog and twipic work fine. I hate to say
this but I am almost convince that the pain in the development process
comes from some outage in either twitpic or Twitter Oauth Echo
authentication.

for the sake of completeness of this thread here it is my 2 working
views : http://dpaste.com/203292/

Regards,
--yml

On Jun 4, 9:59 am, Yann Malet <yann.ma...@gmail.com> wrote:
> I have just uploaded the same image using the web interface :http://twitpic.com/1ttrlu
> <http://twitpic.com/1ttrlu>do you have any recommendation ? On how to solve
> this issue.
>  <http://twitpic.com/1ttrlu>Regards,
> --yml
> >> > >>>http://github.com/zbowling/python-oauth2(thefork I maintain with
> >> bunch
> >> > >>> of twitter related fixes and workarounds)
> >> > >>> or:
> >> > >>>http://github.com/simplegeo/python-oauth2(theofficial upstream)
> ...
>
> read more »

Steve C

unread,
Jun 7, 2010, 9:56:09 AM6/7/10
to Twitter Development Talk
If you were seeing a 400 Bad Req, you were most likely sending a bad
upload to the API. We only return a 400 Bad Req if the image is not
found, the multipart form-data is malformed, or if the image is >5MB.

If Twitpic is having a service outage you will always get a 50x error
(502 or 500). If Twitter is having an OAuth Echo outage, you will get
a 401 Unauthorized from the Twitpic API.

Steve Corona
Twitpic
> > >> > >>>http://github.com/zbowling/python-oauth2(theforkI maintain with
> > >> bunch
> > >> > >>> of twitter related fixes and workarounds)
> > >> > >>> or:...
>
> read more »
Reply all
Reply to author
Forward
0 new messages