Back to blog index

Upgrade Django social auth because Google drops OpenID support

Google has announces that they will drop OpenID support on April 20th.

We use OpenID to authenticate users with their Google account, so this affects Bratabase directly. We have over 6000 accounts that use this login method.

Our code base was using an old version of Django-social-auth to handle the third party login, which was outdated. So this was a good opportunity to update to the new library Python social auth.

My doubt was, if I would need to do any migrations of the authentication information stored on the database to comply with any of the new provided authentication options. Most importantly Oauth2 or Google+.

I decided to go with OAuth2 since it feels less intrusive to users. Going the G+ route feels like too much integration and, to me, and to many users it may scare away that we'll integrate with their social stuff, which I'm not currently interested on.

The migration from Django-social-auth to Python-social-auth was mostly painless following the migration guide that they provide. Also take a look at these extra steps.

About my before mentioned doubt. To make the migration seamless you need to make sure that the users get associated by email. That is, by the @gmail.com email address they used to sign in originally. That will ensure that the new login method using Oauth2 would find the existing user and just perform an association seamlessly and move forward. The user will need to grant the required Oauth2 permissions once, but after that it just works.

There's a problem though, if the user signed up with a Gmail.com address and then decided to change their address, the library would not find the user and end up creating a parallel account with their @gmail.com address, this is clearly not what I wanted.

To solve that problem, I had to make sure that the user was not looked up only on the current users' emails addresses but also on the social authentication credentials for Google, that will contain the original email they used. What I had to do is edit the authentication pipeline implemented by Python social auth, and use my version of the associate_by_email step, where I make the following change on how to find users:

    user_ids = set(User.objects.filter(email__iexact=email).values_list(
        'pk', flat=True))
    associations = set(UserSocialAuth.objects.filter(
        uid__iexact=email).values_list('user_id', flat=True))
    users = User.objects.filter(pk__in=user_ids | associations)

Look how I find the users from both sources instead of just looking at the Users' table. That took care of one of the problems.

A second issue I found was a probably long standing bug on the site. When a user signs up using a social network, they could provide a desired username and it would get created with it by default, if such username existed, Python social auth would append a UUID4 sting to it ensuring it is unique. The problem? That when Python social auth looks up for an existing username it doesn't ignore casing, which would create a separate account based on capitalization.

To address that, again, I changed the pipeline's get_username function where I just changed the username's lookup to use the __iexact modifier.

One last issue. After making the upgrade I found that Reddit's login did not work anymore. Turns out that on the new library the credential settings changed, so I had to change that on my settings file.

With those changes, it seems that we're good to go. It was an easy first upgrade step and will now allow us to easily add more supported authentication methods, like Twitter and Facebook. I am just hating the Nascar we'll end up showing on the login page :-/

April 5, 2015
comments powered by Disqus