Google OAuth2.0 SDK(Google Identity Services) doesn't work on Django 4.0

Hello,
I’m having difficulty using Django 4.0 with Google OAuth2.0 SDK.
I wrote down the specific way to reproduce the problem because this is a bit tricky issue to explain in words.
Please leave a comment, if you have any questions.

TL;DR
Django 4.x and Google OAuth2.0 SDK(new way) conflict for some reasons.
Anyone who is using Google OAuth2.0 SDK with Django 4x?


The problem

Google OAuth2.0 SDK(Google Identity Services) doesn’t work on Django 4.0.x and 4.1.x but works on Django <= 3.2.x
( * The old way of Google OAuth2.0 SDK still works, but will be completely deprecated after March 31, 2023 )


Test Environments

Python 3.9.13
Python 3.10.4
&
Django 3.2.14
Django 4.0.6
Django 4.0b1

How to setup the test env

$ git clone https://github.com/smallbee3/django-oauth-template.git

$ cd django-oauth-template
$ pip install -r requirements.txt

# Need to fill in "client_id"
$ vi mysite/frontend/templates/implicitflow_new_1_gis_only.html
$ vi mysite/frontend/templates/implicitflow_new_2_gapi_async_await.html
$ vi mysite/frontend/templates/implicitflow_new_3_gapi_callback.html

# Need to fill in "apiKey" & "clientId"
$ vi mysite/frontend/templates/implicitflow_old_1_gapi_client_library.html
$ vi mysite/frontend/templates/implicitflow_old_2_js_client_library.html
...

implicitflow_new_1_gis_only.html

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      var access_token;

      function initClient() {
        console.log('Hello initClient!');
        client = google.accounts.oauth2.initTokenClient({
          client_id: 'YOUR_CLIENT_ID',
          ...
        });
      }

You need to replace “YOUR_CLIENT_ID” with your Google Client ID

( * To get your Google Client ID from Google, please refer to below links )
(I deleted the links because I couldn’t add link addresses more than two)

( * To get your Google API Key from Google, please refer to below links )
(I deleted the links because I couldn’t add link addresses more than two)


How to reproduce the problem

$ cd django-oauth-template
$ cd mysite
$ python manage.py runserver

And then, open browser

http://localhost:8000/new1

Test results

There are many different ways to implement Google OAuth2.0 SDK. So I tried every way as below.
https://developers.google.com/identity/oauth2/web/guides/migration-to-gis#implicit_flow_examples

Google Identity Services > Implicit flow examples > The new way >

(1) GIS only : localhost:8000/new1 - django3.x (O), django4.x (X)

(Django 3.2.14 & Django 4.0.6)

(2) GAPI async/await : localhost:8000/new2 - django3.x (O), django4.x (X)
(3) GAPI callback : localhost:8000/new3 - django3.x (O), django4.x (X)


Google Identity Services > Implicit flow examples > The old way >
(4) GAPI Client Library : localhost:8000/old1 - django3.x (O), django4.x (O)
(5) JS Client Library : localhost:8000/old2 - django3.x (O), django4.x (O)


Google Identity Services > Authorization code flow examples > The new way >
(6) Server-side Web Apps : localhost:8000/new4 - django3.x (O), django4.x (X)


As you can see the results above, Google Identity Services codes are not working on django 4.x.
But, strangely, the old version of Google SDK which doesn’t use callback is working well on both Django 3.x and 4.x.

Thus, In my humble opinion, the major reason seems that the callback function inside of Google SDK which is rendered by Django code isn’t called.

mysite/frontend/templates/implicitflow_new_1_gis_only.html

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      ...
      function initClient() {
          ...
          callback: (tokenResponse) => {
            console.log('Hello callback!');
            access_token = tokenResponse.access_token;
            console.log('access_token: ', access_token);
          },
        });
      }
     ...

Other trials

On a side note, I compared the request and response from Google Auth Server between Django 3.x and 4.x. and there was no difference.
So, I think Google Auth Server has no problem with regard to this issue but Google Client library served by Django does have an issue.

Google Client library (accounts.google.com/gsi/client)

(Response from Google Auth Server on Django 3.2.14)

[[["gf.sisr",6,null,null,null,null,null,["gf.cr",4,null,null,[4,null,null,null,["{\n  \"access_token\" : \"ya29.A0AVA9y1sCNWa5H1iHI3Ebjjo4OGX551lV1...63\",\n  \"token_type\" : \"Bearer\",\n  \"expires_in\" : 3598,\n  \"scope\" : \"email profile openid https://www.googleapis.com/auth/calendar.readonly https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/contacts.readonly https://www.googleapis.com/auth/userinfo.email\",\n  \"authuser\" : \"0\",\n  \"hd\" : \"test.com\",\n  \"prompt\" : \"none\"\n}","753749545716-dg8sl....apps.googleusercontent.com","auth712297","http://localhost:8000",null,1]],null,null,[]]],["gf.ttu",1],["e",3,null,null,891]]]

(Response from Google Auth Server on Django 4.0.6)

[[["gf.sisr",6,null,null,null,null,null,["gf.cr",4,null,null,[4,null,null,null,["{\n  \"access_token\" : \"ya29.A0AVA9y1viWoIqts1eK57kJEEOXKK2NJrW86O99FPmmLRabPVkceigfo5B5xa-RDfIuEdymAyJz52I4udUU...Wp1ZHI4a19BY0t3MDVZQ3U0UEhkeUdHVDBLUQ0163\",\n  \"token_type\" : \"Bearer\",\n  \"expires_in\" : 3599,\n  \"scope\" : \"email profile https://www.googleapis.com/auth/calendar.readonly https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email openid https://www.googleapis.com/auth/contacts.readonly\",\n  \"authuser\" : \"0\",\n  \"hd\" : \"test.com\",\n  \"prompt\" : \"none\"\n}","753749545716-dg....apps.googleusercontent.com","auth717087","http://localhost:8000",null,1]],null,null,[]]],["gf.ttu",1],["e",3,null,null,891]]

Plus, I tried testing this Google SDK code with “webpack-dev-server” without using Django rendering, and it works fine.
That’s why I suspect that the updated Django rendering code in v4.0 is the cause of the problem.


Lastly, also tried changing the template engine from django-template to Jinja to see if template engine is the cause of the issue, but still problem remains.

Here are links that I deleted on the above post.

( * To get your Google Client ID from Google, please refer to below links
https://youtu.be/xH6hAW3EqLk
https://www.balbooa.com/gridbox-documentation/how-to-get-google-client-id-and-client-secret )

And for Google API Key which is needed to test the old version of Google OAuth SDK…

( * To get your Google API Key from Google, please refer to below links
https://youtu.be/feM25lZkLkA )

Updates 2022-07-22

I tested Google OAuth2.0 SDK on Flask, and it works well without any issue…

1 Like

The same problem:
GIS in Vuejs project (webpack dev server) works correctly (callback is invoked with token/code), but it does not want to work in bound Django4+VueJS.
I’ve tried to build frontend and run nginx+gunicron+django (frontend is as static) - GIS callback is not invoked…

The problem is in CROSS_ORIGIN_OPENER_POLICY parameter in the response header.
Set SECURE_CROSS_ORIGIN_OPENER_POLICY=None in the settings.py.
https://docs.djangoproject.com/en/4.1/ref/settings/