The simplest way to add Google sign-in to your Django app ✍️

Photo of Tom Dekan
by Tom Dekan

All the guides I've seen about adding Google Sign to Django make it overly complicated (e.g., Django-allauth or Django-social-auth).

We'll use Google sign in the simplest way by:

  1. rendering an HTML page with a Google script tag that adds a sign-in button. When clicked, the button will redirect users to Google for sign-in.
  2. after sign in, Google will redirect the user (with a POST) to a specified page on our site.
  3. we'll get the user's Google information (e.g., email) from the POST request


The finished product using Django and Google sign-in will look like this ✍️:


I've also made a simple video guide (featuring me 🏇🏿) that follows the below instructions. Here's the video:

Let's get started 🚀

0. Setup our Django app

  • Install packages and create our Django app
pip install django python-dotenv google-api-python-client
django-admin startproject core .
python manage.py startapp sim
  • Add our app sim to the INSTALLED_APPS in settings.py:
# settings.py
INSTALLED_APPS = [
    'sim',
    ...
]

This might be foreign to you, but it's quick to do (despite Google Cloud Platform's confusing documentation).

a. Create a project

  • Open the Credentials page of the Google APIs console.
  • Create a Google APIs project.
  • Select your project. This is a gotcha: you need to select your project after you create it. Select your project
  • Click Credentials > Create credentials > OAuth client ID.
  • Click Configure the consent screen > External > Create. Complete the form (I added example.com as the Authorized domain).
  • Add scopes to determine what information you want to access (I added email) > Save and Continue.
  • Add test Google account users (I added my email) > Save and Continue.
  • Click Back to Dashboard

c. Create an OAuth client ID

  • Click Credentials > Create credentials > OAuth client ID > Web application.

Add your authorized Javascript origins

For our local development, we add both http://localhost and http://localhost:8000 to Authorized JavaScript origins.

Substitute the port number with the port number you use for your local development server.

(Later, when deploying to production, you'll need to add the URI of your website to Authorized JavaScript origins. The URI includes the scheme and fully qualified hostname only. For example, https://www.example.com.)

Add your Authorized redirect URIs

  • Add http://localhost:8000/auth-receiver to Authorized redirect URIs.

This is the URL to which Google will send credentials and redirect the user after they have authenticated. Substitute the port number with the port number you use for your local development server.Substitute the port number with the port number you use for your local development server.

Create and copy

  • Click create and copy the Client ID and Client Secret.

d. Add the Client ID to our Django app

  • Create a file called .env at core/.env and add the below to it. We'll use this to store our environment variables, which we won't commit to version control.
GOOGLE_OAUTH_CLIENT_ID=<your_client_id>
  • Add the following to the top of core/settings.py to load the environment variables from the .env file when the server restarts:
import os
from dotenv import load_dotenv


load_dotenv()

Create your Google sign in flow

Our sign in flow is simple and effective. We'll:

  1. render an HTML page, containing a script tag from Google that runs when the user visits the page and adds the Google sign in button
  2. after the user signs in on Google, Google will then redirect the user to a url on our site ('auth-reciever') with a POST request containing a token.
  3. we'll check that the token is valid and get the user's information from it

a. Create a sign in page

  • Create a folder called templates at sim/templates and create a file called sign_in.html in it.
  • Add the below to sign_in.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login Page</title>
    <script src="https://accounts.google.com/gsi/client" async></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f4;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
        }

        .container {
            background-color: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            text-align: center;
        }

        img {
            border-radius: 50%;
            width: 100px;
            height: 100px;
            object-fit: cover;
            margin-top: 10px;
        }

        p {
            color: #333;
            margin: 10px 0;
        }

        a {
            color: #007bff;
            text-decoration: none;
            font-weight: bold;
        }

        a:hover {
            text-decoration: underline;
        }

        .g_id_signin {
            margin-top: 20px;
        }
    </style>
</head>
<body>

<div class="container">
    {% if request.session.user_data %}
    <div>
        <p>Hi {{ request.session.user_data.given_name }} 🙂</p>
        <p>Your email is {{ request.session.user_data.email }}</p>
        <img src="{{ request.session.user_data.picture }}" alt="User picture">
        <p>Click here to <a href="/sign-out">Sign out</a></p>
    </div>
    {% else %}
    <div>
        <p>Hi there 🙂 </p>
        <p>Click below to sign in with Google</p>
        <!--            Paste the generated HTML code for Google sign in button goes here-->
    </div>
    {% endif %}
</div>

</body>
</html>

This includes the script tag to load the Google sign-in API and the button to trigger the sign-in flow.

b. Generate Google sign in button HTML

Now we'll generate the specific HTML to add the button for your app.

To do this, visit the Google HTML generator here.

It should look like this:

Google HTML generator

  • For Google client ID, enter your OAuth client ID.
  • For Login URL, enter: http://localhost:8000/auth-receiver
  • On the option between 'redirect' and 'popup', I selected 'redirect' for simplicity . If you want to use a popup, you'll need to search online for how to set your Cross-Origin-Opener-Policy header to same-origin-allow-popups.
  • Select the sign in methods you want (I selected both 'Enable Sign in with Google button' and 'Enable Google One Tap').
  • Click 'Get code' and copy the HTML code.

c. Add the HTML code to your sign in page

  • Paste the HTML code that you've just generated into your sign_in.html file where you want the button to appear.

Create your views

  • Add the below views to sim/views.py:
import os

from django.http import HttpResponse
from django.shortcuts import render, redirect
from django.views.decorators.csrf import csrf_exempt
from google.oauth2 import id_token
from google.auth.transport import requests
import jwt


def sign_in(request):
    return render(request, 'sign_in.html')


@csrf_exempt
def auth_receiver(request):
    """
    Google calls this URL after the user has signed in with their Google account.
    """
    token = request.POST['credential']

    try:
        user_data = id_token.verify_oauth2_token(
            token, requests.Request(), os.environ['GOOGLE_OAUTH_CLIENT_ID']
        )
    except ValueError:
        return HttpResponse(status=403)

    # In a real app, I'd also save any new user here to the database. See below for a real example I wrote for Photon Designer.
    # You could also authenticate the user here using the details from Google (https://docs.djangoproject.com/en/4.2/topics/auth/default/#how-to-log-a-user-in)
    request.session['user_data'] = user_data

    return redirect('sign_in')


def sign_out(request):
    del request.session['user_data']
    return redirect('sign_in')


Q. How would I save the user to the database in a production app? 🏭

In a real app, you'd want to save the user to the database after we authenticate them with Google.

I didn't add this to the main guide to keep things simpler. But Hope asked me about it on the Youtube video today.

So here's some code that I wrote today for Photon Designer to do that. Feel free to use it 👍



from django.http import HttpResponse, HttpRequest
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from rest_framework.views import APIView
from . import models

@method_decorator(csrf_exempt, name='dispatch')
class AuthGoogle(APIView):
    """
    Google calls this URL after the user has signed in with their Google account.
    """
    def post(self, request, *args, **kwargs):
        try:
            user_data = self.get_google_user_data(request)
        except ValueError:
            return HttpResponse("Invalid Google token", status=403)

        email = user_data["email"]
        user, created = models.User.objects.get_or_create(
            email=email, defaults={
                "username": email, "sign_up_method": "google",
                "first_name": user_data.get("given_name"),
            }
        )

        # Add any other logic, such as setting a http only auth cookie as needed here.
        return HttpResponse(status=200)

    @staticmethod
    def get_google_user_data(request: HttpRequest):
        token = request.POST['credential']
        return id_token.verify_oauth2_token(
            token, requests.Request(), os.environ['GOOGLE_OAUTH_CLIENT_ID']
        )

Connect your urls

  • Include the app's URLs in the core/urls.py file:
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('sim.urls')),
]
  • Create a urls.py file in the sim directory with the below code:
from django.urls import path
from . import views

urlpatterns = [
    path('', views.sign_in, name='sign_in'),
    path('sign-out', views.sign_out, name='sign_out'),
    path('auth-receiver', views.auth_receiver, name='auth_receiver'),
]

  • Run your migrations to create the database tables for our app (So that we can store the user's information):
python manage.py migrate

Run your app and test your Google sign in

  • Run your app, making sure that the address and port number matches the port number you added to your Authorized Javascript origins and Authorized redirect URIs.
python manage.py runserver 8000

Congrats - You've added Google sign in to your Django app 🎉

By reducing the effort to use your app, by adding Google sign in to your Django app, you'll increase the ratio of visitors who become users 👩‍🦱

You'll still need people to visit your app, and to provide them with loads of value. But you've increased your ability to demonstrate that value.

Next steps: Overview of deploying to production

Deploying your Google sign in to production is also fast to do. As an overview, you'd need to:

  1. Add your production URL to the 'Authorized Javascript origins' and 'Authorized redirect URIs' in your Google Cloud Platform project (like we did earlier for localhost).
  2. Update your .env file with your production Client ID and Client Secret.
  3. Change the data-login_uri="http://localhost:8000/auth-receiver" in your sign_in.html file to your production URL (use a context variable that changes based on the environment).

Also, if you're looking for a specific tutorial on how to add Google sign in with Django REST Framework, check out Zach's article here.

P.S Build Django frontend faster than a cheetah chasing a gazelle? ⚡️

Do you dream of creating Django products so quickly they break the space-time continuum? Yeah, me too.

I'm building: Photon Designer. It's a visual editor that puts the 'fast' in 'very fast.'

When Photon Designer starts up, it slings Django templates at you faster than light escaping a black hole (In a good way).

Let's get visual.

Do you want to create beautiful frontends effortlessly?
Click below to book your spot on our early access mailing list (as well as early adopter prices).
Copied link to clipboard 📋

Made with care by Tom Dekan

© 2024 Photon Designer