Retrieving contacts with gdata.contacts.client and oauth2 - python

I am using oAuth2WebServerFlow to get an oAuth access token and then retrieve a list of a user's contacts. I'm using web2py as the web framework.
flow = oauth2client.client.OAuth2WebServerFlow(client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
scope='https://www.google.com/m8/feeds',
user_agent=USER_AGENT)
callback = 'http://127.0.0.1:8000/Test/searcher/oauth2callback'
authorise_url = flow.step1_get_authorize_url(callback)
session.flow = pickle.dumps(flow)
redirect(authorise_url)
With the redirect then being handled as follows
flow = pickle.loads(session.flow)
credentials = flow.step2_exchange(request.vars)
My question is how to change the OAuth2Credentials object returned above into an OAuth2AccessToken object, that I can then use to authorise a request to the contacts library with something like:
gc = gdata.contacts.client.ContactsClient(source="")
token.authorize(gc)
gc.GetContacts
I've tried various methods with no success, normally getting an oAuth2AccessTokenError message of "Invalid Grant". I'm thinking something like this may work but also think there must be a simpler way!
token = gdata.gauth.OAuth2Token(client_id=CLIENT_ID, client_secret=CLIENT_SECRET, scope='https://www.google.com/m8/feeds', user_agent=USER_AGENT)
token.redirect_uri = 'http://127.0.0.1:8000/Test/searcher/oauth2callback'
token.get_access_token(<<code to pass the access_token out of the Credentials object??>>)
Can anyone help with this?

I managed to get this working. It was pretty straightforward actually, I just stopped using the OAuth2WebServerFlow, which didn't seem to be adding much value anyway. So the new code looks like this:
token = gdata.gauth.OAuth2Token(client_id, client_secret, scope, ua)
session.token = pickle.dumps(token)
redirect(token.generate_authorize_url(redirect_uri='http://127.0.0.1:8000/Test/default/oauth2callback'))
Followed by
def oauth2callback():
token = pickle.loads(session.token)
token.redirect_uri='http://127.0.0.1:8000/Test/default/oauth2callback'
token.get_access_token(request.vars.code)
gc = gdata.contacts.client.ContactsClient(source='')
gc = token.authorize(gc)
feed = gc.GetContacts()
Hope this is helpful to someoone!

Assuming you have code for newer OAuth2.0 APIs setup correctly, you can get this working by creating a Token class that modifies headers that converts Credentials -> Token class.
OAUTH_LABEL='OAuth '
#Transforms OAuth2 credentials to OAuth2 token.
class OAuthCred2Token(object):
def __init__(self, token_string):
self.token_string = token_string
def modify_request(self, http_request):
http_request.headers['Authorization'] = '%s%s' % (OAUTH_LABEL,
self.token_string)
ModifyRequest = modify_request
You can test it as follows:
gc = gdata.contacts.client.ContactsClient(source='')
token = OAuthCred2Token(creds.access_token)
gc.auth_token = token
print gc.GetContacts()
Note that this code will not handle token refreshes, which code using credentials handles.
In my own application, it is acceptable to make a simple call using a service to refresh the credentials before making a call to get contacts.

Related

How do I verify a tweepy API using 3 legged auth?

I've been following the instructions in the tweepy documentation:
https://docs.tweepy.org/en/stable/authentication.html
When I pass in an oauth_verifier to get a user's access tokens, it throws out:
tweepy.errors.TweepyException: 'oauth_token'
#views.route("/")
def home():
with open("oauth1_user_handler", "rb") as userHandler:
oauth1_user_handler=pickle.load(userHandler)
oauth_verifier = request.args.get("oauth_verifier")
user_access_token, user_access_token_secret = oauth1_user_handler.get_access_token(
oauth_verifier
)
return "<p>user_access_token, user_access_token_secret</p>."
I've tried multiple variations of passing in the oauth_verifier, the oauth_token, and combinations of the 2, exactly as they are in the url parameters, but that hasn't worked either.
Any help would be greatly appreciated.
Since you're reinitializing OAuth1UserHandler and not using the same instance, you need to set the request token and secret before using the verifier to get the access token and secret.
There's a section on this in the documentation you linked: https://tweepy.readthedocs.io/en/v4.10.1/authentication.html#legged-oauth

Yahoo Oauth2 step 3

I am trying to create a quick web app that authenticates into a users Yahoo account, but I am having trouble getting 'user approval'.
Yahoo Auth Page
Personally, every time I go to external website and have to authenticate, I usually log into my account. This seems to be redirecting me to a page and asking for a code. I have 0 idea what code I would need to supply in order to authenticate. And if I dont know, my users certainly wont! I am building a flask app, and I have tried to model my code around this repo.
I have added some code specifically for Yahoo, but cant seem to connect the dots. New YahooSignIn subclass in the oauth.py file below:
class YahooSignIn(OAuthSignIn):
def __init__(self):
super(YahooSignIn, self).__init__('yahoo')
self.service = OAuth2Service(
name='yahoo',
consumer_id=self.consumer_id,
consumer_secret=self.consume_secret,
authorize_url='https://api.login.yahoo.com/oauth/v2/request_auth',
access_token_url='https://api.login.yahoo.com/oauth/v2/get_token',
base_url='http://fantasysports.yahooapis.com/'
)
def authorize(self):
return redirect(self.service.get_authorize_url(
scope='email',
response_type='code',
redirect_uri=self.get_callback_url())
)
def callback(self):
def decode_json(payload):
return json.loads(payload.decode('utf-8'))
if 'code' not in request.args:
return None, None, None
oauth_session = self.service.get_auth_session(
data={'code': request.args['code'],
'grant_type': 'authorization_code',
'redirect_uri': self.get_callback_url()},
decoder=decode_json
)
me = oauth_session.get('me?fields=id,email').json()
return (
'yahoo$' + me['id'],
me.get('email').split('#')[0],
me.get('email')
)
The only other change made was to the index.html page to add an additional link with a 'yahoo' parameter
<p>Login with Yahoo</p>
Any help would be greatly appreciated as this one has stumped me the last two nights and I would love to move past this!
Previous to this year (2018/19) I had been using Yahoo's Oauth 1.0 API. This year I ran into problems using it so I switched to using Oauth 2.0 via the yahoo-oauth library linked below. They have a nice page that describes how to use their library. Here is the code that I used.
from yahoo_oauth import OAuth2
class YahooFantasyAPI:
def fetchGameID(self):
session = self.getSession()
r = session.get(
'https://fantasysports.yahooapis.com/fantasy/v2/game/nfl'
)
print(r.text)
def getSession(self):
oauth = OAuth2(None, None, from_file='oauth2.json')
if not oauth.token_is_valid():
oauth.refresh_access_token()
return oauth.session
api = YahooFantasyAPI()
fetchGameID()
https://yahoo-oauth.readthedocs.io/en/latest/

python: GraphAPIError: Invalid OAuth access token

I'm making a web app in python using the Flask framework to request the access token from Facebook using the SDK supplied in their site.
The access token is returned and it is correctly set in the GraphAPI object. However, it is returning the following error:
GraphAPIError: Invalid OAuth access token.
If I query the graph API from my local python environment using the same access token, it works just fine. The problem seems to be when executing in the webserver.
See code snippet below:
#app.route('/facebook')
def fb():
if 'token' in session:
graph = facebook.GraphAPI(session['token'])
return graph.get_object("me")
#app.route('/facebook/login')
def fblogin():
code = request.args.get('code','')
if(code == ""):
args = dict(client_id=app_id, redirect_uri=request.base_url)
#args = dict(client_id=app_id, redirect_uri=request.url_root + 'facebook')
return redirect(
"https://graph.facebook.com/oauth/authorize?" +
urllib.urlencode(args))
else:
token = facebook.get_access_token_from_code(code, request.base_url, app_id, app_secret)
session['token'] = [token.itervalues().next()]
return redirect (request.url_root + 'facebook')
Has anyone faced this before and/or can provide some insights?
Ok, 2 issues that I have managed to correct in this code and get it working:
1) The following line of code makes a list, that why the GraphAPI object is not able to identify a valid access token:
session['token'] = [token.itervalues().next()]
2) The following line of code gives an error stating that 'dict' is not callable. This is because the returned variable is a dictionary and, in order to be returned as a view, one must first transform it into a string:
return graph.get_object("me")

Twython - How to associate multiple twitter accounts with one user

I want to allow registered users to add multiple twitter accounts. I followed twython-django example, and got a working version of one user - one twitter account. If the user tries to use twitter login again, follows same view again, I get this error: Invalid / expired Token.
I tried adding force_login=true to oauth/authorize and oauth/authenticate, removing 'request_token' from request.session dict, but i still get Invalid Token error during get_authentication_tokens().
How to properly associate multiple twitter accounts with the same user, using twython? What am I missing here?
Here is an a twython-django example: https://github.com/ryanmcgrath/twython-django/blob/master/twython_django_oauth/views.py
My view:
def twitter_login(request):
redirect_back_to_url = request.build_absolute_uri()
if 'request_token' not in request.session:
# request authorization tokens
t = Twython(twitter_token=settings.TWITTER_CONSUMER_KEY,
twitter_secret=settings.TWITTER_CONSUMER_SECRET,
callback_url=redirect_back_to_url)
# Request an authorization url to send the user to...
request_oauth_key = t.get_authentication_tokens()
# signing current session as one with twitter authentication
request.session['request_token'] = request_oauth_key
# redirecting the user to twitter authorization url for authentication
return HttpResponseRedirect(request_oauth_key['auth_url'])
else:
# user authenticated, receiving auth token
t2 = Twython(twitter_token=settings.TWITTER_CONSUMER_KEY,
twitter_secret=settings.TWITTER_CONSUMER_SECRET,
oauth_token=request.session['request_token'][
'oauth_token'],
oauth_token_secret=request.session['request_token'][
'oauth_token_secret'])
oauth_key = t2.get_authorized_tokens()
# save authorized tokens
# twitter oauth tokens dont expire
token = Token.objects.get_or_create(account_name=oauth_key['screen_name'],
token=oauth_key['oauth_token'],
secret=oauth_key['oauth_token_secret'])
user = request.user.get_profile()
user.twitter.add(token[0].id)
user.save()
logger.info('Successfully acquired twitter oauth token.')
return HttpResponseRedirect(reverse('profile'))
Update: possible solution
I changed my view to this:
def twitter_login(request):
redirect_back_to_url = request.build_absolute_uri()
if 'request_token' not in request.session:
# request authorization tokens
t = Twython(twitter_token=settings.TWITTER_CONSUMER_KEY,
twitter_secret=settings.TWITTER_CONSUMER_SECRET,
callback_url=redirect_back_to_url)
# Request an authorization url to send the user to...
request_oauth_key = t.get_authentication_tokens()
# signing current session as one with twitter authentication
request.session['request_token'] = request_oauth_key
# redirecting the user to twitter authorization url for authentication
return HttpResponseRedirect(request_oauth_key['auth_url'])
else:
# user authenticated, receiving auth token
t2 = Twython(twitter_token=settings.TWITTER_CONSUMER_KEY,
twitter_secret=settings.TWITTER_CONSUMER_SECRET,
oauth_token=request.session['request_token'][
'oauth_token'],
oauth_token_secret=request.session['request_token'][
'oauth_token_secret'])
oauth_key = t2.get_authorized_tokens()
if 'screen_name' not in oauth_key:
del request.session['request_token']
request.session.modified = True
return HttpResponseRedirect(reverse('twitter_login'))
# save authorized tokens
# twitter oauth tokens dont expire
token = Token.objects.get_or_create(account_name=oauth_key['screen_name'],
token=oauth_key['oauth_token'],
secret=oauth_key['oauth_token_secret'])
user = request.user.get_profile()
user.twitter.add(token[0].id)
user.save()
logger.info('Successfully acquired twitter oauth token.')
return HttpResponseRedirect(reverse('profile'))
And not sure yet if this had anything to do with it. I added after line 272 in twython.py request_args['force_login'] = True. But, as i said, i'm not sure if that had any impact, cos according to https://dev.twitter.com/docs/api/1/post/oauth/request_token force login is not one of the optional args.
Some voodoo this was. lol.
Tell me if its a total rubbish.
Mmm, I believe OP got it working/right, but just as a quick breakdown, twython-django isn't built to support multiple account associations (it's also not on Django 1.5, so be careful with that until it's updated~).
You'd need to do what OP did and set up a separate table for Tokens that match over to a User, and then handle which account they're currently using by pulling the appropriate tokens. OPs use of force_login also seems to have worked because, while it's not necessarily documented, I believe it still works (according to this thread, unless I'm misreading it - if I am, I would love to be corrected).
I don't expect this answer to be accepted as I'm not really solving anything, but if anyone else encounters this I'm hoping to leave something more clear-cut than the above notes. Hope that's alright!

Im using python (django framework) to gain a request token from google api, but the request token always comes back empty

Here is sample code that I'm working with.
def index(request):
flow = OAuth2WebServerFlow(
client_id='xyz.apps.googleusercontent.com',
client_secret='xyz',
scope='https://www.googleapis.com/auth/plus.me',
user_agent='sample/1.0')
callback = 'http://%s/oauth2callback' % request.META[ 'HTTP_HOST' ]
authorize_url = flow.step1_get_authorize_url(callback)
return HttpResponse(flow)
For some reason 'flow' is always set to " " or empty instead of a request token. I have searched for days on this issue.
Can anyone tell me why I can't get a request token from google using this method?
fyi: I know that I should be redirecting the user to the authorize url, but I want to see if flow is set before I do since Google will provide the authorize url even if a request token wasn't returned.
Before you can use OAuth 2.0, you must register your application using
the Google APIs Console. After you've registered, go to the API Access
tab and copy the "Client ID" and "Client secret" values, which you'll
need later.
http://code.google.com/p/google-api-python-client/wiki/OAuth2#Registering
If this answer actually helps with your problem then I must bid an R.I.P. to S.O.

Categories