Django SocialAuth Fix Google Email Open id attribute exchange
Django Social auth is a package that enables login to your django website with Facebook, Google, Yahoo and Twitter. Allowing authentication from 3rd party websites which supports open authentication helps users easy to register to your website without filling too much details. Easier signup makes more registrations and helps you cover your django web hosting charges :D . The package is managed at github here, but it does not have a stable release yet.
One of the issues is the bug in open id attribute exchange of the "email" field when using Google for authentication. The fix is pretty simple, Google requires the type_uri of email to be set to http://axschema.org/contact/email. Thus we have to change the OPENID_AX settings in localsettings.py to
OPENID_AX = [{"type_uri": "http://axschema.org/contact/email",
"count": 1,
"required": True,
"alias": "email"}]
The other change is in the code which reads the openid parameters when login completes in socialauth/auth_backends.py. Here is the complete openid authentication backend code with the fix.
class OpenIdBackend:
def authenticate(self, openid_key, request, provider):
try:
assoc = UserAssociation.objects.get(openid_key = openid_key)
return assoc.user
except UserAssociation.DoesNotExist:
#fetch if openid provider provides any simple registration fields
nickname = None
email = None
if request.openid and request.openid.sreg:
email = request.openid.sreg.get('email')
nickname = request.openid.sreg.get('nickname')
elif request.openid and request.openid.ax:
if provider == 'Google':
email = request.openid.ax.get('http://axschema.org/contact/email')
email = email.pop()
else:
email = request.openid.ax.get('email')
nickname = request.openid.ax.get('nickname')
if nickname is None :
nickname = ''.join([random.choice('abcdefghijklmnopqrstuvwxyz') for i in xrange(10)])
if email is None :
valid_username = False
email = None #'%s@example.openid.com'%(nickname)
else:
valid_username = True
name_count = User.objects.filter(username__startswith = nickname).count()
if name_count:
username = '%s%s'%(nickname, name_count + 1)
user = User.objects.create_user(username,email or '')
else:
user = User.objects.create_user(nickname,email or '')
user.save()
#create openid association
assoc = UserAssociation()
assoc.openid_key = openid_key
assoc.user = user
if email:
assoc.email = email
if nickname:
assoc.nickname = nickname
if valid_username:
assoc.is_username_valid = True
assoc.save()
#Create AuthMeta
auth_meta = AuthMeta(user = user, provider = provider)
auth_meta.save()
return user
def get_user(self, user_id):
try:
user = User.objects.get(pk = user_id)
return user
except User.DoesNotExist:
return None
With these fixes the openid login with google should fetch you the email. :)