31

I'm not really sure what I'm doing. Should I be using a library for this? Or do it manually?

So I'm trying to do some work with the WiThings (http://www.withings.com/api) API in Python.

In order to perform some of the requests, OAuth authentication is required. I have gone through using the requests library and obtained an oauth token and secret token, alongside my consumer and consumer secret tokens.

Now I am at the point of having to make requests, and I am running into some problems. The format for the request I need to make is as follows (an example from their API):

http://wbsapi.withings.net/notify?action=subscribe
&callbackurl=http%3a%2f%2fwww.yourdomain.net%2fyourCustomApplication.php
&comment=Your%20Own%20Application%20Description
&oauth_consumer_key=c331c571585e7c518c78656f41582e96fc1c2b926cf77648223dd76424b52b
&oauth_nonce=accbac1b7ee2b86b828e6dc4a5a539b2
&oauth_signature=XfobZMboIg2cRyNKAvyzONHHnKM%3D
&oauth_signature_method=HMAC-SHA1
&oauth_timestamp=1311842514
&oauth_token=887557411788d5120537c6550fbf2df68921f8dd6f8c7e7f9b441941eb10
&oauth_version=1.0
&userid=831

As far as I can tell, this is pretty much a typical format with OAuth, except for the userid at the end.

So, is it possible for me to make a request like this using the requests library? Or some other library? How do I get the URL right, with the comment and userid and callbackurl fields? Or do I need to generate this URL manually? If that's the case, whats the best way for going about doing this?

Any assistance is greatly appreciated, as I've been stuck on this for a while.

EDIT

So, for some clarification, I understand about 98% of the code I am being referred to. I am only having a little problem at the end.

So here I am, with the following code:

from __future__ import unicode_literals
from urlparse import parse_qs
import requests
from requests_oauthlib import OAuth1Session

consumer_key = '**Valid consumer key**'

consumer_secret = '**Valid consumer secret**'


oauth_key = '**Valid oauth key obtained through requests library and OAuth workflow**'

oauth_secret ='**Valid oauth secret obtained through requests library and OAuth workflow**'

verifier = '**Valid consumer key obtained through requests library and OAuth workflow**'

base_url = 'http://wbsapi.withings.net/notify'

params = {
'action': 'subscribe',
'callbackurl': '**callback URL**',
'comment': '**comment**',
'oauth_consumer_key': '**consumer_key**',
'oauth_nonce': 'etc etc',
'oauth_signature' : '' # <-------------- Where do I get this
# etc etc... I have everything else
}
r = requests.get("http://wbsapi.withings.net/notify", params=params)

This is all I need. I have everything I need but the signature. Is there a way I can get the signature from the oauth libraries? This is all that has been holding me up.

elykl33t
  • 887
  • 6
  • 11
  • 24
  • Have you seen https://requests-oauthlib.readthedocs.org/en/latest/ yet? – Martijn Pieters Jul 22 '13 at 13:12
  • Yes, but I couldn't figure out from the documentation exactly how I would construct the request when something needs to be put at the end of the URL, in this case userid. – elykl33t Jul 22 '13 at 13:22
  • I see [support for extra information](https://requests-oauthlib.readthedocs.org/en/latest/oauth2_workflow.html#all-define-the-token-token-saver-and-needed-credentials) in the documentation. – Martijn Pieters Jul 22 '13 at 13:29
  • The thing at the end of the URL is called query string :) – woozyking Jul 22 '13 at 13:33
  • Does "OAuth 2" refer to the OAuth version? If so, WiThings is version 1. – elykl33t Jul 22 '13 at 13:34
  • Also checkout [rauth](https://github.com/litl/rauth), which has an identical API to Requests. (It loosely wraps Requests, has been around longer than oauthlib, and is actively maintained and developed.) – maxcountryman Jul 22 '13 at 23:32

2 Answers2

57

To perform GET requests with URL query string:

import requests

params = {
    'action': 'subscribe',
    'callbackurl': '',
    'comment': '',
    'oauth_consumer_key': '',
    'oauth_nonce': '',
    # more key=value pairs as appeared in your query string
}
r = requests.get("http://wbsapi.withings.net/notify", params=params)

With that cleared, now you just need to follow the workflow documented on http://www.withings.com/en/api/oauthguide and implement them

  1. Upon receiving your OAuth Key and OAuth Secret, perform a GET request with the following endpoint and query string which will give you back token:

    https://oauth.withings.com/account/request_token? oauth_callback=http%3A%2F%2Fexample.com%2Fget_access_token &oauth_consumer_key=c331c571585e7c518c78656f41582e96fc1c2b926cf77648223dd76424b52b &oauth_nonce=f71972b1fa93b8935ccaf34ee02d7657 &oauth_signature=J8xzgFtHTsSRw8Ejc8UDV2jls34%3D &oauth_signature_method=HMAC-SHA1 &oauth_timestamp=1311778988 &oauth_version=1.0

  2. Then you need to authorize the token you received with the following request which will give you the user_id:

    https://oauth.withings.com/account/authorize? oauth_callback=http%3A%2F%2Fexample.com%2Fget_access_token &oauth_consumer_key=c331c571585e7c518c78656f41582e96fc1c2b926cf77648223dd76424b52b &oauth_nonce=369f9ceb2f285ac637c9a7e9e98019bd &oauth_signature=OR9J9iEl%2F2yGOXP2wk5c2%2BWtYvU%3D &oauth_signature_method=HMAC-SHA1 &oauth_timestamp=1311778988 &oauth_token=5bb105d2292ff43ec9c0f633fee9033045ed4643e9871b80ce586dc1bf945 &oauth_version=1.0

  3. Then you need to request the access_token by hitting this endpoint with some more query string:

    https://oauth.withings.com/account/access_token? oauth_consumer_key=c331c571585e7c518c78656f41582e96fc1c2b926cf77648223dd76424b52b &oauth_nonce=7acd22371fc56fd8a0aaf8416f79f84f &oauth_signature=jmj1g%2FB3rYR2DCpWp86jB5YVHIM%3D &oauth_signature_method=HMAC-SHA1 &oauth_timestamp=1311778988 &oauth_token=5bb105d2292ff43ec9c0f633fee9033045ed4643e9871b80ce586dc1bf945 &oauth_version=1.0 &userid=831

  4. Now you have everything needed to perform the aforementioned request in your question, and others, example directly from the documentation:

    http://wbsapi.withings.com/measure? action=getmeas &oauth_consumer_key=c331c571585e7c518c78656f41582e96fc1c2b926cf77648223dd76424b52b &oauth_nonce=accbac1b7ee2b86b828e6dc4a5a539b2 &oauth_signature=XfobZMboIg2cRyNKAvyzONHHnKM%3D &oauth_signature_method=HMAC-SHA1 &oauth_timestamp=1311842514 &oauth_token=887557411788d5120537c6550fbf2df68921f8dd6f8c7e7f9b441941eb10 &oauth_version=1.0 &userid=831

Again, everything can be done without explicit oauth library as you can finish the workflow with requests.get and query string built from a dict feed into the params argument of the method.

I truly hope this helps you achieve your goal.

woozyking
  • 4,880
  • 1
  • 23
  • 29
  • I had thought of this, the problem being I would have to manually generate the OAuth signature, which is a bit of a pain, and I am not sure if I could get it right. – elykl33t Jul 22 '13 at 13:35
  • @elykl33t Then use `requests-oauthlib` to perform the signing procedure and obtain aforementioned parameters, then construct a `GET` request with __query string__ as mentioned in my answer. – woozyking Jul 22 '13 at 13:36
  • This is something I have thought about, but I was not sure how to do. How could I obtain the signature from the request? A big reason I am having issues with this is just because my Python experience is lacking. – elykl33t Jul 22 '13 at 13:40
  • @elykl33t These are all clearly documented on WIthings API documentation: http://www.withings.com/en/api/oauthguide, starting from the section on "How to get this permanent access ?", then read through https://requests-oauthlib.readthedocs.org/en/latest/oauth1_workflow.html#workflow-example-showing-use-of-both-oauth1-and-oauth1session on how to implement it using `requests-oauthlib` – woozyking Jul 22 '13 at 13:45
  • Thanks for all the help, and sorry for all the questions, but in an OAuth1 session, is the rsa_key the signature? – elykl33t Jul 22 '13 at 13:52
  • @elykl33t I understand the pain of working with various `APIs` online nowadays, that's why I've put together the whole workflow (really just copy/paste from withings doc with my notes). Hopefully you can achieve what you're looking for. – woozyking Jul 22 '13 at 14:08
  • sorry I keep coming back to here.... But my question is really very specific. I understand everything you are saying, but it is leaving one thing out: In the params, I need the signature. But I don't know where to get the signature from or how to generate it. I added information to the original post. Thanks again. – elykl33t Jul 22 '13 at 14:22
1

Here's a working example using the rauth client library. Full disclosure, I'm the original rauth author. Hope this helps:

from rauth import OAuth1Service

withings = OAuth1Service(
        name='withings',
        consumer_key='fd5fe4002db502983fbd056fdf416941d83e15ecb68ee9eeb4978cb2370c',
        consumer_secret='29dbc46056c530814c2debcf24c76ff42f6cc66d0e3e5cfdef1e166725c6f',
        base_url='http://wbsapi.withings.net/notify',
        request_token_url='https://oauth.withings.com/account/request_token',
        authorize_url='http://oauth.withings.com/account/authorize',
        access_token_url='https://oauth.withings.com/account/access_token')

request_token, request_token_secret = withings.get_request_token()

callback = 'https://github.com/litl/rauth'

authorize_url = withings.get_authorize_url(request_token,
                                           oauth_callback=callback)

print('Visit this URL in your browser: {url}'.format(url=authorize_url))
userid = raw_input('Enter userid from browser URL: ')

sess = withings.get_auth_session(request_token,
                                 request_token_secret,
                                 params={'userid': userid})

print sess.get('measure', params={'action': 'getmeas',
                                  'userid': userid}).json()
maxcountryman
  • 1,562
  • 1
  • 24
  • 51