Django Register with Oauth – Yahoo!

Continuing the oauth series but before we begin, read the overview / disclaimer. On to Yahoo!…

For this tutorial you will need Oauth2 installed.

First off, ensure that you have registered your application with Yahoo! and have created the following in your settings file:

# https://developer.apps.yahoo.com/projects
YAHOO_CONSUMER_KEY = 'YOUR-APP-ID'
YAHOO_CONSUMER_SECRET = 'YOUR-APP-SECRET'

view raw
settings.py
hosted with ❤ by GitHub

1) Create the redirect URL

Yahoo is a little bit more complicated than the previous providers in that the first step requires you to get a request token before redirecting to Yahoo!. Much like the other examples, this also requires a redirect URL and the consumer key, but we also have some new data that’s required including a timestamp, nonce (any unique string), version and language.

Once you’ve got the request token, you can use it to create the authorization URL.

import urllib2
import urlparse
import time
import oauth2 as oauth
from django.conf import settings
from django.core.urlresolvers import reverse
from django.core.context_processors import csrf
def get_authorization_url(request):
# URL to where we will redirect to
redirect_url = settings.SITE_URL + reverse('register_yahoo')
# set the api URL
url = 'https://api.login.yahoo.com/oauth/v2/get_request_token'
# required params for yahoo
params = {
'oauth_callback': redirect_url,
'oauth_timestamp': str(int(time.time())),
'oauth_nonce': unicode(csrf(request)['csrf_token']),
'oauth_version': '1.0',
'xoauth_lang_pref': 'en-us'
}
# create the consumer
consumer = oauth.Consumer(key=settings.YAHOO_CONSUMER_KEY, secret=settings.YAHOO_CONSUMER_SECRET)
# create the request
req = oauth.Request(method='GET', url=url, parameters=params)
# sign the request
signature_method = oauth.SignatureMethod_PLAINTEXT()
req.sign_request(signature_method, consumer, None)
# get the request token from yahoo
response = urllib2.urlopen(req.to_url()).read()
# parse the response
params = urlparse.parse_qs(response)
# store the returned values
request.session['yahoo_oauth_token'] = params['oauth_token'][0]
request.session['yahoo_oauth_token_secret'] = params['oauth_token_secret'][0]
# get the authorization URL
url = 'https://api.login.yahoo.com/oauth/v2/request_auth?oauth_token=' + params['oauth_token'][0]
return url

view raw
yahoo.py
hosted with ❤ by GitHub

2) Redirect to provider’s site

This url can now be used to redirect to Yahoo! (i.e. HttpResponseRedirect(url)):

3) Handle the response (approved or denied)

Once the user makes their choice to approve or deny, Yahoo! will redirect back to your redirect_url. You will need to verify the user approved the application:

def verify(request):
# ensure we have a session token and the token value is the same as what yahoo returned
if 'yahoo_oauth_token' not in request.session \
or 'oauth_token' not in request.GET \
or 'oauth_verifier' not in request.GET \
or request.session['yahoo_oauth_token'] != request.GET['oauth_token']:
return False
else:
return True

view raw
yahoo.py
hosted with ❤ by GitHub

If any of the above tests fail, we can safely assume the user either arrived at this page directly (i.e. by typing in the URL) or they denied the application. Either way we don’t want to proceed and should redirect them to the start of the registration flow (i.e. HttpResponseRedirect(reverse('register'))).

4 & 5) Get an access token and the user’s profile

At this point the user has authorized your application but you don’t have actual access to their data yet. To get that you’ll need to request an access token. Notice that we’re saving the access token to the user’s session as we don’t want to request it more than once during the registration flow.

Once you have the access token, you can then make the request for the user’s profile data:

import urllib2
import urlparse
import time
import json
import re
import oauth2 as oauth
from django.conf import settings
def get_user_data(request):
data = {}
# if we don't have a token yet, get one now
if 'yahoo_access_token' not in request.session:
# set the api URL
url = 'https://api.login.yahoo.com/oauth/v2/get_token'
# required params for yahoo
params = {
'oauth_timestamp': str(int(time.time())),
'oauth_nonce': unicode(csrf(request)['csrf_token']),
'oauth_version': '1.0',
'xoauth_lang_pref': 'en-us',
'oauth_verifier': request.GET['oauth_verifier']
}
# create the consumer and token
consumer = oauth.Consumer(key=settings.YAHOO_CONSUMER_KEY, secret=settings.YAHOO_CONSUMER_SECRET)
token = oauth.Token(key=request.session['yahoo_oauth_token'], secret=request.session['yahoo_oauth_token_secret'])
# create the request
req = oauth.Request(method='GET', url=url, parameters=params)
# sign the request
signature_method = oauth.SignatureMethod_PLAINTEXT()
req.sign_request(signature_method, consumer, token)
# get the request token from yahoo
response = urllib2.urlopen(req.to_url()).read()
# parse the response
params = urlparse.parse_qs(response)
# store the returned values
request.session['yahoo_guid'] = params['xoauth_yahoo_guid'][0]
request.session['yahoo_access_token'] = params['oauth_token'][0]
request.session['yahoo_access_token_secret'] = params['oauth_token_secret'][0]
# set the url using the user id
url = 'http://social.yahooapis.com/v1/user/%s/profile?format=json' % request.session['yahoo_guid']
consumer = oauth.Consumer(key=settings.YAHOO_CONSUMER_KEY, secret=settings.YAHOO_CONSUMER_SECRET)
token = oauth.Token(key=request.session['yahoo_access_token'], secret=request.session['yahoo_access_token_secret'])
# get the user's data from yahoo
client = oauth.Client(consumer, token)
response, content = client.request(url)
# grab the profile from the response
user = json.loads(content)['profile']
# split the name
full_name = user['nickname'].split(' ', 1)
# get the user's info
data['user_id'] = user['guid']
data['username'] = re.sub('[^0-9a-zA-Z]+', '', user['nickname']).lower()
data['email'] = user['emails'][0]['handle'] if 'handle' in user['emails'][0] else ''
data['full_name'] = user['nickname']
data['first_name'] = full_name[0] if len(full_name) > 0 else ''
data['last_name'] = full_name[1] if len(full_name) >= 2 else ''
data['timezone'] = user['timeZone']
data['picture'] = user['image']['imageUrl']
return data

view raw
yahoo.py
hosted with ❤ by GitHub

That’s it! You can now use the user’s profile information to pre-fill a registration form, perhaps skipping over fields where you already have a required value such as an email address or first and last name. Just be sure to save their Yahoo! ID along with their profile so you can use it validate them in the future. You should also save the access_token and expires values so that you can make future requests to the API for this user or refresh the access token when it has expired.

In a future post I’ll be looking at how to detect an already registered user as well as provide a login with this provider button.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s