Devdelly

Adding Google OAuth to Django

September 21, 2019

We all love how simple it is to set an application up with django. Recently I wondered how I could allow my users to log in via their existing Google accounts.

In the following tutorial we will create a simple Django application and add a Google Login button to our login page.

Project setup

First we need to set up a basic project with a login page and simple userprofile page. The profile page should only be accessible to logged in users.

django-admin startproject google_login_project
cd google_login_project
python manage.py migrate

Change google_login_project/urls.py to

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('admin/', admin.site.urls),
    path('accounts/', include('django.contrib.auth.urls')),
    path('accounts/profile', TemplateView.as_view(template_name='registration/profile.html')),
]

Which adds the /accounts/login/ and /accounts/logout/ routes to our application. We’re also setting the additional route /accounts/profile here, which displays our userprofile page.

Next we need a html template for the login page. Add the following to templates/registration/login.html

<h1>Login</h1>
<form method="post">
  {% csrf_token %} {{ form.as_p }}
  <button>Login</button>
</form>

and templates/registration/profile.html

{% if user.is_authenticated %} You are logged in as {{ user.username }} {% else
%}
<a href="/accounts/login">Login</a>
{% endif %}

We also want to set the login_url and login_redirect_url in our settings.py file:

LOGIN_URL = '/accounts/login'
LOGIN_REDIRECT_URL = '/accounts/profile'

This should be it for our basic setup! Let’s give it a test spin via: python manage.py runserver If we visit localhost:8000/accounts/login we’ll see our (beautiful) login page and localhost:8000/accounts/profile gives us our profile page.

Adding Google Authentication

Now to the fun part! Let’s add a Google login to our page.

Installing the package

First we need to install the social-auth-app-django package:

pip install social-auth-app-django

And add the app to settings.py:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'social_django', # new
]

After which we need to migrate:

python manage.py migrate

Settings

Now we need to set several other settings:

SocialAuthExceptionMiddleware which handles exceptions during the social auth process:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'social_django.middleware.SocialAuthExceptionMiddleware', # new
]

We also need to add the backends and login_redirect context processors to TEMPLATES:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'social_django.context_processors.backends',    # new
                'social_django.context_processors.login_redirect',  # new
            ],
        },
    },
]

In order to enable our login to use GoogleOAuth2 for the authentication we need to add an authentication_backend:

AUTHENTICATION_BACKENDS = (     # new
    'social_core.backends.google.GoogleOAuth2',
    'django.contrib.auth.backends.ModelBackend',
)

And provide a list of features we want to use in the social_auth_pipeline:

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

SOCIAL_AUTH_STRATEGY = 'social_django.strategy.DjangoStrategy'  # new
SOCIAL_AUTH_STORAGE = 'social_django.models.DjangoStorage'  # new

Lastly we need to configure our OAUTH2 KEY and SECRET in settings.py:

# ...
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'your-google-oauth-2-key-goes-here' # new
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'your-google-oauth-2-secret-goes-here'   # new
# ...

If you don’t already have a key and secret. Here’s how to obtain them:

Go to the Google Developers Console and click the create button, to create a new project. After that go to the credentials tab and select Create Credentials and then OAuth Client ID. The type of the application is a Web app.

For the Authorized redirect URIs we need to add:

http://localhost:8000/auth/complete/google-oauth2/
http://127.0.0.1:8000/auth/complete/google-oauth2/

This should give you the key and secret for your application.

Adding social auth to our application

For the OAuth2 flow to work our application needs to provide some endpoints, we can easily add them by including the provided endpoints from the package:

In urls.py:

from django.conf.urls import url
from django.contrib import admin
from django.urls import include, path
from django.views.generic import TemplateView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('accounts/', include('django.contrib.auth.urls')),
    path('accounts/profile/', TemplateView.as_view(template_name='registration/profile.html')),
    url(r'^auth/', include('social_django.urls', namespace='social')),  # new
]

And that should be it!

Let’s add the google login button to the loginform templates/registration/login.html:

<h1>Login</h1>
<form method="post">
  {% csrf_token %} {{ form.as_p }}
  <button>Login</button>
</form>
<a href="{% url 'social:begin' 'google-oauth2' %}">Login with Google</a> # new

Links

python-social-auth package


A blog by Manuel about everything related to software development