Google sign-in REST API with python-social-auth and Django REST Framework

Florian Abel
CodeX
Published in
6 min readJul 19, 2022

Authenticate your Django backend for users that sign up with Google, Facebook, or other third-party OAuth providers in your frontend or mobile application.

TL;DR: The GitHub repo for this project can be found here.

Photo by Ed Hardie on Unsplash

Introduction

In this article, you are building REST API endpoints for social authentication. They can be used with a separate frontend like a Single-Page or Mobile Application. We will be using python-social-auth together with Django REST Framework (DRF) to exchange an access token obtained by a third-party OAuth provider (GoogleOAuth2) with an authentication token from DRF.

Note: We will only work with API endpoints and not be using Djangos' built-in template language in this example.

The authentication process

Authentication with OAuth2 offers different flows, depending on the specific setup you are using for your application. The basics and which flow to choose for your project are covered well in these two articles from Aaron Parecki and Auth0.

In this example, we are using the Authorization Code Flow with Proof Key for Code Exchange (PKCE), which is the recommended way when public clients, like Single-Page and Mobile Applications, request an access token from an OAuth2 provider. The authentication process with the provider happens on the client, which after successful authentication exchanges the received access token for another authentication token from the backend. With this token, the client can then be authenticated to use the APIs provided by the backend.

Further details about this flow are well explained in this Auth0 article. The exception in our case is, that we are connecting directly to GoogleOAuth2, instead of Auth0.

Is this the right social authentication package for me?
Note: If you are unsure if this is the best package for your use case, you can find a brief comparison between four popular social authentication packages for Django in this article.

Prerequisites

Django

Before we start I am asking you to install and set up your Django project. If you are unsure of how to do that, please check the ‘Get started with Django’-documentation.

Django REST Framework

We are using Django REST Framework (DRF) for setting up the REST API endpoints and a basic understanding of it is recommended. The scope of this Article will not cover much about DRF itself, however, the information provided in its ‘Quickstart’-Tutorial will be more than enough to follow along here.

Obtaining an access token

To test your application you will need a GoogleOAuth2 access token. This would usually be obtained by your frontend, like a Single-Page or Mobile Application. For development purposes, you can also do that by using a web browser and curl, as described here.

Note: Make sure to request the required scope to adequately populate your user model, when sending the OAuth request with the client.
For GoogleOAuth2 it is:
scope = ['email', 'profile'] .

Getting Started

Assuming that you have set up your Django Project and have already applied your initial migrations, let’s start by adding a new app called users. In there we are building our authentication logic:

python manage.py startapp users

Next, we install the required third-party packages.

pip install django \djangorestframework \social-auth-core \social-auth-app-django

After installation, we register the users and external apps in our settings.py:

Finally, we run the migrations that come with DRF and python-social-auth.

python manage.py migrate

For PostgreSQL users:
In this example, we are using the SQLite3 database, that Django uses by default. If you are working with a PostgreSQL database, it is recommended to use the built-in JSONB field for storing the extracted
extra_data , by adding this line to your settings.py: SOCIAL_AUTH_JSONFIELD_ENABLED = True

For MongoEngineORM users:
If you are using the
MongoEngine ORM, installation and setup vary slightly. Please check the official docs of python-social-auth.

Configuration

Token-based authentication and permission classes from DRF

For DRF we are adding a few entries into our settings.py to define authentication and permission classes.

Settings for DRF

Authentication
By adding rest_framework.authtoken to our INSTALLED_APPS and adding TokenAuthentication to the list of default authentication classes, we enabled DRFs built-in token authentication. It provides a simple token-based HTTP Authentication scheme.

In our example, we are exchanging the access token received from the social provider in our frontend for one of these tokes. It can then be used to authenticate against our protected API endpoints.

Note: This is not a very secure authentication scheme and is used only for presentation purposes. For production-level applications, you want to consider a more secure alternative.

Permissions
By default, all API requests need to be authenticated with this setting. We can change this behavior on APIs that are intended to be public, later on.

Authentication backends

Django keeps a list of authentication backends, to iterate through on an authentication request. It defaults to Django’s basic authentication backend but can be extended or replaced as necessary. In this example, we are adding a backend for GoogleOAuth2 authentication. You can find a full list of available options with python-social-auth, here.

Note: If the entry AUTHENTICATION_BACKENDS does not exist, you must create it yourself.

Social auth pipeline

Pipeline mechanisms are used to handle authentication, association, and disconnection flows in python-social-auth. Default flows exist for these pipelines and can be adjusted as required (Adding custom functions; Removing default items).

The default authentication pipeline can be found, here. To define your own, you can add it to your settings.py.

Note: In this example, we use the default pipeline, without adding our own version. However, you can find an example version below.

Creating the API endpoints

We will use a registration endpoint to register/login a user with an access token from a social provider (GoogleOAuth2). This endpoint will be open to the public. Furthermore, we are defining a second endpoint that can be used with the authentication tokens handed out by our backend.

Creating the view

The @psa() decorator

The @psa() decorator is the key piece of our view. It connects our view with python-social-auth and adds details to the request object.

  • The social strategy (In our case, Django)
  • The social authentication backend to use (In our case, GoogleOAuth2), based on the backend argument in our view.
  • Providing the redirect URL (In our case: None. We perform the authentication on the client-side)

Note: Unfortunately, the @psa() decorator is barely mentioned in the official documentation of python-social-auth, but some additional information can be found in this StackOverflow post.

Adding URLs

Testing our API

Register/Login user

With the access token obtained from our client we can now test our API:

curl -X POST \http://127.0.0.1/api/register-by-access-token/social/google-oauth2/ \-H 'Accept: application/json' \-H 'Content-Type: application/json' \-d '{"access_token": "<GoogleOAuth2-ACCESS-TOKEN-FROM-CLIENT>"}'

This should yield something like: {"token": "<TOKEN-FROM-BACKEND"} .

Test returned token

Using the received authentication token from our backend, we can now access the protected endpoint.

curl \http://127.0.0.1/api/authentication-test/ \-H 'Accept: application/json' \-H 'Content-Type: application/json' \-H 'Authorization: Token fd4d4cca9163e5afb251f6310b9c725413979f10'

{"message": "User successfully authenticated"}

Summary

You now have a simple REST API endpoint to create and log in Google users. To receive access, simply exchange an access token obtained with your frontend for an authentication token of your backend. To use other authentication providers like Facebook or Twitter, follow the same principle with a different authentication backend.

Feel free to post your questions/comments in the comments or hit me up on Twitter (@florian_abel_). I’d be happy to hear your thoughts, questions, and experiences.

--

--

Florian Abel
CodeX
Writer for

Techie & Builder | Python, Flutter, Machine Learning/Data Science