How to integrate Google One Tap login with django-allauth?

1.2k views Asked by At

How does one integrate the Google One Tap login experience with django-allauth?

  1. django-allauth is integrated and working great for simple username/password logins.
  2. I have Google OneTap's nicer user experience recognizing the user's authenticated Google account and offering to continue via that, sending a JWT auth token to Django.
  3. Trying to find the simplest / cleanest way to register the new user account with the OneTap token and treat them as authenticated.

Appreciate any suggestions.

Refs:

2

There are 2 answers

3
Leon Wei On BEST ANSWER

[Update Feb 8, 2024] Added a step by step tutorial on how to implement Google One Tap Login with Django

Hacked something together, not as slick as one click login, (takes one extra step)

See more details here https://twitter.com/DataLeonWei/status/1368021373151375361

All I did was changing the google redirect URL to the existing user log-in page with Google.

And add an additional view and replace google's data-login_uri with this view's URL.

@csrf_exempt
def google_one_tap_login(request):
    login_url = PUBLIC_DOMAIN_NAME + '/accounts/google/login/'
    return HttpResponseRedirect(login_url)

If someone has a better solution, please let me know.

My current hack is implemented on both sqlpad and skills.ai, please feel free to check them out and see it in action.

5
Rok Strniša On

Override allauth's account/login.html template and render the Google button (remember to replace <GOOGLE_APP_CLIENT_ID> and <HOMEPAGE>):

<div class="g_id_signin" data-type="standard" data-shape="pill"
     data-theme="outline" data-text="signin_with" data-size="large"
     data-logo_alignment="left"></div>

<div id="g_id_onload"
     data-client_id="<GOOGLE_APP_CLIENT_ID>"
     data-context="signin"
     data-ux_mode="redirect"
     data-login_uri="<HOMEPAGE>{% url 'google-login' %}?next={{ request.GET.next }}"
     data-auto_prompt="false"></div>

<script src="https://accounts.google.com/gsi/client" async defer></script>

Install google-auth if you haven't already:

pip install google-auth

Register the google-login endpoint in your urls.py:

path('google-login', views.google_login, name='google-login'),

Define the google-login endpoint in your views.py, where you verify the Google ID token before redirecting to allauth's login URL for Google:

import logging
from django.conf import settings
from django.contrib import messages
from django.http import HttpResponseBadRequest
from django.shortcuts import redirect
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from google.oauth2 import id_token
from google.auth.transport import requests
from urllib import parse

@csrf_exempt
@require_POST
def google_login(request):
    body_unicode = request.body.decode('utf-8')
    body_params = parse.parse_qs(body_unicode)
    csrf_token_cookie = request.COOKIES.get('g_csrf_token')
    if not csrf_token_cookie:
        return HttpResponseBadRequest('No CSRF token in Cookie.')
    csrf_token_body = body_params.get('g_csrf_token')
    if not csrf_token_body:
        return HttpResponseBadRequest('No CSRF token in post body.')
    if csrf_token_cookie != csrf_token_body[0]:
        return HttpResponseBadRequest('Failed to verify double submit cookie.')
    next_url = request.GET['next']
    try:
        token = body_params.get('credential')[0]
        # noinspection PyUnusedLocal
        idinfo = id_token.verify_oauth2_token(token, requests.Request(), settings.GOOGLE_APP_CLIENT_ID)
    except ValueError as e:
        logging.error(e)
        return HttpResponseBadRequest('Failed to verify Google auth credentials.')
    return redirect(settings.HOMEPAGE + '/accounts/google/login/?next=' + next_url)