2

Trying to create google login for django using googleapiclient and oauth2client.

I am able to open home page, and getting redirected to google login successfully. Once after sign-in, it is redirecting to home page where I'm receiving this error.

Reference link/tutorial

views.py

import httplib2

from googleapiclient.discovery import build
from django.http import HttpResponseBadRequest
from django.http import HttpResponseRedirect
from .models import CredentialsModel
from gfglogin import settings
from oauth2client.contrib import xsrfutil
from oauth2client.client import flow_from_clientsecrets
from oauth2client.contrib.django_util.storage import DjangoORMStorage
from django.shortcuts import render
from httplib2 import Http


def home(request):
    print("*****home*****")
    status = True

    if not request.user.is_authenticated:
        return HttpResponseRedirect('admin')

    storage = DjangoORMStorage(CredentialsModel, 'id', request.user, 'credential')
    credential = storage.get()
    print(f"credential: {credential}")
    print(f"storage: {storage}")

    try:
        access_token = credential.access_token
        resp, cont = Http().request("https://www.googleapis.com/auth/gmail.readonly",
                                    headers={'Host': 'www.googleapis.com',
                                            'Authorization': access_token})
    except:
        status = False
        print('Not Found')

    return render(request, 'index.html', {'status': status})


################################
#   GMAIL API IMPLEMENTATION   #
################################

# CLIENT_SECRETS, name of a file containing the OAuth 2.0 information for this
# application, including client_id and client_secret, which are found
# on the API Access tab on the Google APIs
# Console <http://code.google.com/apis/console>


FLOW = flow_from_clientsecrets(
    settings.GOOGLE_OAUTH2_CLIENT_SECRETS_JSON,
    scope='https://www.googleapis.com/auth/gmail.readonly',
    redirect_uri='http://127.0.0.1:8080/oauth2callback',
    prompt='consent')


def gmail_authenticate(request):
    print("*****gmail_authenticate*****")
    storage = DjangoORMStorage(CredentialsModel, 'id', request.user, 'credential')
    credential = storage.get()
    print(f"credential: {credential}")
    if credential is None or credential.invalid:
        FLOW.params['state'] = xsrfutil.generate_token(settings.SECRET_KEY,
                                                       request.user)
        authorize_url = FLOW.step1_get_authorize_url()
        return HttpResponseRedirect(authorize_url)
    else:
        http = httplib2.Http()
        http = credential.authorize(http)
        service = build('gmail', 'v1', http=http)
        print('access_token = ', credential.access_token)
        status = True

        return render(request, 'index.html', {'status': status})


def auth_return(request):
    print("*****auth_return*****")
    get_state = bytes(request.GET.get('state'), 'utf8')
    if not xsrfutil.validate_token(settings.SECRET_KEY, get_state,
                                   request.user):
        return HttpResponseBadRequest()
    credential = FLOW.step2_exchange(request.GET.get('code'))
    print(f"credential: {credential}")
    storage = DjangoORMStorage(CredentialsModel, 'id', request.user, 'credential')
    storage.put(credential)
    print(f"storage: {storage}")
    print("access_token: %s" % credential.access_token)
    return HttpResponseRedirect("/")

Error:

System check identified no issues (0 silenced).
June 06, 2020 - 14:38:49
Django version 3.0.7, using settings 'gfglogin.settings'
Starting development server at http://127.0.0.1:8080/
Quit the server with CTRL-BREAK.
[06/Jun/2020 14:39:00] "GET /admin/ HTTP/1.1" 200 3042
*****home*****
credential: None
storage: <oauth2client.contrib.django_util.storage.DjangoORMStorage object at 0x0000014A630EABE0>
Not Found
[06/Jun/2020 14:39:05] "GET / HTTP/1.1" 200 327
*****gmail_authenticate*****
credential: None
[06/Jun/2020 14:39:07] "GET /gmailAuthenticate HTTP/1.1" 302 0
*****auth_return*****
credential: <oauth2client.client.OAuth2Credentials object at 0x0000014A6322BA00>
storage: <oauth2client.contrib.django_util.storage.DjangoORMStorage object at 0x0000014A6322B550>
access_token: ya29.a0AfH6SMBLyCWC3cV4iiMk0jWUJaw8ruUFoBqFTkM5LT2acAc6FelcoADU3tn67RslO-24dKEFqrdp4tcLFVuEIMvmn7cHKeb8XeZ9YNQozRoRSTU6hs-jMA9bHP10epw1ImbBaY8SUgQUtF75mRRniR0aELEmzTVKGe8
[06/Jun/2020 14:40:26] "GET /oauth2callback?state=VaASAVe2IusAHCsQfc7EfToxNTkxNDM0NTQ3&code=4/0gFCWPMx4qTUrv4wUWpSKbA8Z_rTaZb-YGGDRrK4NsK2UiW6f4MpA_g1Pr5RpyGcRxbCtWlH6qHvKIJvbpG_L9c&scope=https://www.googleapis.com/auth/gmail.readonly HTTP/1.1" 302 0
*****home*****
Internal Server Error: /
Traceback (most recent call last):
  File "D:\PERSONAL DATA\env\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
    response = get_response(request)
  File "D:\PERSONAL DATA\env\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "D:\PERSONAL DATA\env\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "D:\PERSONAL DATA\raw_login\google-oauth-mail\gfgauth\views.py", line 23, in home
    credential = storage.get()
  File "D:\PERSONAL DATA\env\lib\site-packages\oauth2client\client.py", line 407, in get
    return self.locked_get()
  File "D:\PERSONAL DATA\env\lib\site-packages\oauth2client\contrib\django_util\storage.py", line 58, in locked_get
    if len(entities) > 0:
  File "D:\PERSONAL DATA\env\lib\site-packages\django\db\models\query.py", line 258, in __len__
    self._fetch_all()
  File "D:\PERSONAL DATA\env\lib\site-packages\django\db\models\query.py", line 1261, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "D:\PERSONAL DATA\env\lib\site-packages\django\db\models\query.py", line 74, in __iter__
    for row in compiler.results_iter(results):
  File "D:\PERSONAL DATA\env\lib\site-packages\django\db\models\sql\compiler.py", line 1096, in apply_converters
    value = converter(value, expression, connection)
TypeError: from_db_value() missing 1 required positional argument: 'context'

One of SO post, suggest to replace context argument with *args, **kwargs. I'm not able to see from_db_value method in source code.

versions:

django == 3.0.7

python == 3.8

Can anyone please respond to this question and help?

I have also seen that oauth2client is depreciated. Is there any other library with clear example that I can follow? or Can anyone post example code?

In github issue, someone says

You can't use oauth2client's storage with google-auth. google-auth credentials are relatively straight forward to persist, see: https://github.com/GoogleCloudPlatform/google-auth-library-python-oauthlib/blob/master/google_auth_oauthlib/tool/main.py#L80

But, as new to this, I'm not able to understand implement this. Please help!

Python coder
  • 743
  • 5
  • 18

1 Answers1

1

The problem seems to be with oauth2client, which is no longer updated or supported. From the README:

Note: oauth2client is now deprecated. No more features will be added to the libraries and the core team is turning down support. We recommend you use google-auth and oauthlib. For more details on the deprecation, see oauth2client deprecation.

So I'd suggest you take a look at those two packages and integrate those instead.

The takeaway here is that you should be more careful about the tutorials you choose. This one uses Django 2.0, which hasn't been supported for over a year. Always look for tutorials which match either the latest release or the latest LTS release, or you're asking for trouble.

Tom Carrick
  • 6,349
  • 13
  • 54
  • 78
  • Thanks! I have tried for such tutorials, but my bad, not able to find useful links. If possible, can you please share any related tutorials/links? – Python coder Jun 06 '20 at 11:39
  • 1
    If you're looking to get social auth working, I'd try looking at allauth: https://django-allauth.readthedocs.io/en/latest/ - there's no tutorial, but it's fairly easy to use. – Tom Carrick Jun 08 '20 at 15:39