Skip to content

Commit fe9c079

Browse files
author
Randi Cabezas
committed
starting oauth2
1 parent 81428b9 commit fe9c079

File tree

2 files changed

+181
-1
lines changed

2 files changed

+181
-1
lines changed

fitbit/api.py

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
import requests
33
import json
44
import datetime
5+
import base64
56

67
try:
78
from urllib.parse import urlencode
89
except ImportError:
910
# Python 2.x
1011
from urllib import urlencode
1112

12-
from requests_oauthlib import OAuth1, OAuth1Session
13+
from requests_oauthlib import OAuth1, OAuth1Session, OAuth2, OAuth2Session
1314

1415
from fitbit.exceptions import (BadResponse, DeleteError, HTTPBadRequest,
1516
HTTPUnauthorized, HTTPForbidden,
@@ -142,6 +143,133 @@ def fetch_access_token(self, verifier, token=None):
142143
return response
143144

144145

146+
class FitbitOauth2Client(object):
147+
API_ENDPOINT = "https://api.fitbit.com"
148+
AUTHORIZE_ENDPOINT = "https://www.fitbit.com"
149+
API_VERSION = 1
150+
151+
request_token_url = "%s/oauth2/token" % API_ENDPOINT
152+
authorization_url = "%s/oauth2/authorize" % AUTHORIZE_ENDPOINT
153+
access_token_url = request_token_url
154+
refresh_token_url = request_token_url
155+
156+
def __init__(self, client_id , client_secret,
157+
access_token=None, refresh_token=None,
158+
resource_owner_key=None, resource_owner_secret=None, user_id=None,
159+
*args, **kwargs):
160+
"""
161+
Create a FitbitOauth2Client object. Specify the first 7 parameters if
162+
you have them to access user data. Specify just the first 2 parameters
163+
to start the setup for user authorization (as an example see gather_key_oauth2.py)
164+
- client_id, client_secret are in the app configuration page
165+
https://dev.fitbit.com/apps
166+
- access_token, refresh_token are obtained after the user grants permission
167+
- resource_owner_key, resource_owner_secret, user_id are user parameters
168+
"""
169+
170+
self.session = requests.Session()
171+
self.client_id = client_id
172+
self.client_secret = client_secret
173+
self.resource_owner_key = resource_owner_key
174+
self.resource_owner_secret = resource_owner_secret
175+
self.header = {'Authorization': 'Basic ' + base64.b64encode(client_id +':' + client_secret)}
176+
if user_id:
177+
self.user_id = user_id
178+
179+
#params = {'client_secret': client_secret}
180+
#if self.resource_owner_key and self.resource_owner_secret:
181+
#params['resource_owner_key'] = self.resource_owner_key
182+
#params['resource_owner_secret'] = self.resource_owner_secret
183+
#self.oauth = OAuth2Session(client_id, **params)
184+
self.oauth = OAuth2Session(client_id)
185+
186+
def _request(self, method, url, **kwargs):
187+
"""
188+
A simple wrapper around requests.
189+
"""
190+
return self.session.request(method, url, **kwargs)
191+
192+
def make_request(self, url, data={}, method=None, **kwargs):
193+
"""
194+
Builds and makes the OAuth Request, catches errors
195+
196+
https://wiki.fitbit.com/display/API/API+Response+Format+And+Errors
197+
"""
198+
if not method:
199+
method = 'POST' if data else 'GET'
200+
auth = OAuth2(
201+
self.client_id, self.client_secret, self.resource_owner_key,
202+
self.resource_owner_secret, signature_type='auth_header')
203+
response = self._request(method, url, data=data, auth=auth, **kwargs)
204+
205+
if response.status_code == 401:
206+
raise HTTPUnauthorized(response)
207+
elif response.status_code == 403:
208+
raise HTTPForbidden(response)
209+
elif response.status_code == 404:
210+
raise HTTPNotFound(response)
211+
elif response.status_code == 409:
212+
raise HTTPConflict(response)
213+
elif response.status_code == 429:
214+
exc = HTTPTooManyRequests(response)
215+
exc.retry_after_secs = int(response.headers['Retry-After'])
216+
raise exc
217+
218+
elif response.status_code >= 500:
219+
raise HTTPServerError(response)
220+
elif response.status_code >= 400:
221+
raise HTTPBadRequest(response)
222+
return response
223+
224+
def authorize_token_url(self, scope=None, redirect_uri=None, **kwargs):
225+
"""Step 1: Return the URL the user needs to go to in order to grant us
226+
authorization to look at their data. Then redirect the user to that
227+
URL, open their browser to it, or tell them to copy the URL into their
228+
browser.
229+
- scope: pemissions that that are being requested [default ask all]
230+
- redirect_uri: url to which the reponse will posted
231+
required only if your app does not have one
232+
TODO: check if you can give any url and grab code from it
233+
for more info see https://wiki.fitbit.com/display/API/OAuth+2.0
234+
"""
235+
236+
if scope:
237+
self.oauth.scope = scope
238+
else:
239+
#self.oauth.scope = {"heartrate", "location"}
240+
self.oauth.scope = "activity nutrition heartrate location nutrition profile settings sleep social weight"
241+
242+
if redirect_uri:
243+
self.oauth.redirect_uri = redirect_uri
244+
245+
return self.oauth.authorization_url(self.authorization_url, **kwargs)
246+
247+
def fetch_access_token(self, verifier, token=None):
248+
"""Step 3: Given the verifier from fitbit, and optionally a token from
249+
step 1 (not necessary if using the same FitbitOAuthClient object) calls
250+
fitbit again and returns an access token object. Extract the needed
251+
information from that and save it to use in future API calls.
252+
"""
253+
if token:
254+
self.resource_owner_key = token.get('oauth_token')
255+
self.resource_owner_secret = token.get('oauth_token_secret')
256+
257+
self.oauth = OAuth2Session(
258+
self.client_key,
259+
client_secret=self.client_secret,
260+
resource_owner_key=self.resource_owner_key,
261+
resource_owner_secret=self.resource_owner_secret,
262+
verifier=verifier)
263+
response = self.oauth.fetch_access_token(self.access_token_url)
264+
265+
self.user_id = response.get('encoded_user_id')
266+
self.resource_owner_key = response.get('oauth_token')
267+
self.resource_owner_secret = response.get('oauth_token_secret')
268+
return response
269+
270+
271+
272+
145273
class Fitbit(object):
146274
US = 'en_US'
147275
METRIC = 'en_UK'

gather_keys_oauth2.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/usr/bin/env python
2+
import pprint
3+
import sys
4+
import os
5+
6+
import interface
7+
8+
#add the ./python-* folders to paths for ease of importing modules
9+
dirLoc = os.path.dirname(os.path.realpath(__file__))
10+
fitbitDir = dirLoc + '/python-fitbit/'
11+
sys.path.append(fitbitDir)
12+
from fitbit.api import FitbitOauth2Client
13+
14+
15+
if __name__ == '__main__':
16+
17+
client_id = sys.argv[1]
18+
client_sec = sys.argv[2]
19+
20+
# setup
21+
pp = pprint.PrettyPrinter(indent=4)
22+
print('** OAuth Python GET KEYS **\n')
23+
client = FitbitOauth2Client(client.key, client.secret)
24+
25+
## get request token
26+
#print('* Obtain a request token ...\n')
27+
#token = client.fetch_request_token()
28+
#print('RESPONSE')
29+
#pp.pprint(token)
30+
#print('')
31+
32+
#print('* Authorize the request token in your browser\n')
33+
#print(client.authorize_token_url())
34+
#try:
35+
#verifier = raw_input('Verifier: ')
36+
#except NameError:
37+
## Python 3.x
38+
#verifier = input('Verifier: ')
39+
40+
## get access token
41+
#print('\n* Obtain an access token ...\n')
42+
#token = client.fetch_access_token(verifier)
43+
#print('RESPONSE')
44+
#pp.pprint(token)
45+
#print('')
46+
#return(token)
47+
48+
49+
50+
51+
52+

0 commit comments

Comments
 (0)