yeti logo icon
Close Icon
contact us
Yeti postage stamp
We'll reply within 24 hours.
Thank you! Your message has been received!
A yeti hand giving a thumb's up
Oops! Something went wrong while submitting the form.

Integrating Django, Tastypie & Python Social Auth

By
Rudy Mutter
-
April 14, 2014

Want to integrate social auth with Django REST Framework instead? See our complementary piece updated to work with DRF.

Recently for an iOS application we were developing, we needed to allow users to sign up with Facebook, Twitter, or create their own login with an email address. Our backend and API were developed using Django and Tastypie respectively

Python Social Auth is intended for use through the web and has routes already set up for authenticating and disconnecting users from different social media services. It also has tons of different pluggable backends that you can just use out of the box. Unfortunately I could not find any documentation or tutorials on how I could call into the Python Social Auth codebase without using the auto-magicness of the url routes that come with the package.

Pipelines

The first thing you need to understand about Python Social Auth is its pipeline concept. Here is the default pipeline:

SOCIAL_AUTH_PIPELINE = (
   'social.pipeline.social_auth.social_details',
   'social.pipeline.social_auth.social_uid',
   'social.pipeline.social_auth.auth_allowed',
   'social.pipeline.social_auth.social_user',
   'social.pipeline.user.get_username',
   'social.pipeline.user.create_user',
   'social.pipeline.social_auth.associate_user',
   'social.pipeline.social_auth.load_extra_data',
   'social.pipeline.user.user_details'
)

Whenever a user is authenticated, each one of these functions is called in turn. The general workflow is to figure out if the user is authenticated, get their details from the social media provider, create a new UserSocialAuth and User record, and finally fill in any extra details about this user that you've received from the social media provider.

The pipeline is also entirely configurable. This means that you can override this in your settings.py and create your own pipeline functions that do whatever you'd like. For example, we've created a pipeline step that gets the user's profile image from either Facebook or Twitter and saves that in our application.

def get_profile_image(strategy, details, response, uid, user, social, *args, **kwargs):
   """Attempt to get a profile image for the User"""

   if user is None:
       return

   image_url = None
   if strategy.backend.name == "facebook":
       image_url = "https://graph.facebook.com/{0}/picture?type=large".format(uid)
   elif strategy.backend.name == "twitter":
       if response['profile_image_url'] != '':
           image_url = response['profile_image_url']

   if image_url:
       try:
           result = urllib.urlretrieve(image_url)
           user.original_photo.save("{0}.jpg".format(uid), File(open(result[0])))
           user.save(update_fields=['original_photo'])
       except URLError:
           pass

Strategies

Strategies in Python Social Auth are the different frameworks that Python Social Auth supports. Originally we used Django Social Auth on past projects, and it was merged into this one so that code reuse could happen between multiple frameworks (Flask, Django, CherryPy, Pyramid, etc).

Each Strategy basically has framework specific code to plug into Python Social Auth's functionality seamlessly into the framework. We'll obviously be using the Django Strategy to accomplish this integration.

Backends

Python Social Auth comes with a whole lot of backends out of the box. It is also easy to create your own backend if you're trying to integrate with a less common social media provider. For our integration and example we were integrating with Facebook + Twitter, but this solution is pretty agnostic to whatever backend you're using.

To note, in our solution we call backends "providers" or "social media providers", which I've mentioned above previously. This is just so that the iOS application can inform the server which backend the user is trying to authenticate with.

Putting it All Together, Starting Python Social Auth's Pipeline

To review:

1. We pick the Strategy or framework specific code we're trying to implement Python Social Auth with, which is Django in this example.

2. We set up the Pipeline, or chain of functions that will be called in succession to authenticate the user with the Backend of our choice then create a Django User in our application.

Once you have a grasp of these basic concepts, it is actually pretty easy to hook into Python Social Auth programmatically. All we need to do is load the Django Strategy with the Backend we're currently authenticating it with, then tell it to start the Pipeline.

from social.apps.django_app import load_strategy

provider = “facebook”
access_token = “CAAIkpON595IBADC8CqXgq615wfsls15u6RI23sreqbzntau”
strategy = load_strategy(backend=provider)
user = strategy.backend.do_auth(access_token)

To put this in a Tastypie Resource all we have to do is overwrite the obj_create function to do the above logic and make sure we return the user we've just created in the bundle. Here's a simple example of what that would look like.

class SocialSignUpResource(BaseModelResource):

   class Meta:
       queryset = User.objects.all()
       allowed_methods = ['post']
       authentication = Authentication()
       authorization = Authorization()
       resource_name = "social_sign_up"

   def obj_create(self, bundle, request=None, **kwargs):
       provider = bundle.data['provider']
       access_token = bundle.data['access_token']

       strategy = load_strategy(backend=provider)
       user = strategy.backend.do_auth(access_token)
       if user and user.is_active:
           bundle.obj = user
           return bundle
       else:
           raise BadRequest("Error authenticating user with this provider")

To make a request to this resource to sign a user up would be very straightfoward. Here's the example JSON.

{
 "provider":"facebook",
 "access_token":"CAAIkpON595IBADC8CqXgq615wfsl"
}

Rudy Mutter is a CTO + Founding Partner at Yeti. He found his passion for technology as a youth, spending his childhood developing games and coding websites. Rudy now resides in the Yeti Cave where he architects Yeti’s system and heads up project production.

Connect with Rudy on Linkedin

You Might also like...

Shopify Checkout Using UI Extensions

At Yeti we recently created a custom Shopify App using Checkout UI extensions to pull real-time data from a client’s Enterprise Resource Planning (ERP) system into Shopify. By the end of this article you will better understand what Shopify Checkout UI extensions are, how to approach building them, and some of the things to keep in mind during the implementation process.

colorful swirlsAn Introduction to Neural Networks

Join James McNamara in this insightful talk as he navigates the intricate world of neural networks, deep learning, and artificial intelligence. From the evolution of architectures like CNNs and RNNs to groundbreaking techniques like word embeddings and transformers, discover the transformative impact of AI in image recognition, natural language processing, and even coding assistance.

A keyboardThe Symbolicon: My Journey to an Ineffective 10-key Keyboard

Join developer Jonny in exploring the Symbolicon, a unique 10-key custom keyboard inspired by the Braille alphabet. Delve into the conceptualization, ideas, and the hands-on process of building this unique keyboard!

Browse all Blog Articles

Ready for your new product adventure?

Let's Get Started