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:
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 🚀
pip install django python-dotenv google-api-python-client
django-admin startproject core .
python manage.py startapp sim
# settings.py
INSTALLED_APPS = [
'sim',
...
]
This might be foreign to you, but it's quick to do (despite Google Cloud Platform's confusing documentation).
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.)
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.
.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>
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()
Our sign in flow is simple and effective. We'll:
templates
at sim/templates
and create a file called sign_in.html
in it.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.
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:
http://localhost:8000/auth-receiver
Cross-Origin-Opener-Policy
header to same-origin-allow-popups
.sign_in.html
file where you want the button to appear.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')
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']
)
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')),
]
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'),
]
python manage.py migrate
python manage.py runserver 8000
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.
Deploying your Google sign in to production is also fast to do. As an overview, you'd need to:
.env
file with your production Client ID and Client Secret.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.
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).