Wedava
Wedava

Reputation: 1231

Oauth2 using Python 3.4 and Django 1.7

I'm trying to authorize my django application using oauth2 in order to interact with the google content for shopping API. However, I'm experiencing issues with oauth2 along the way.

I have oauth2client and google-api-python-client installed. My view is as follows:

CLIENT_SECRETS = os.path.join(os.path.dirname(__file__), 'client_secret.json')

FLOW = flow_from_clientsecrets(
    CLIENT_SECRETS,
    scope='https://www.googleapis.com/auth/content',
    redirect_uri='https://127.0.0.1:8000/oauth2/oauth2callback')


def get_account_ids(service):
    accounts = service.management().accounts().list().execute()
    ids = []
    if accounts.get('items'):
        for account in accounts['items']:
            ids.append(account['id'])
    return ids


@login_required
def index(request):
    user = request.user
    storage = Storage(CredentialsModel, 'id', user, 'credential')
    credential = storage.get()    
    if credential is None:
        FLOW.params['state'] = xsrfutil.generate_token(
            settings.SECRET_KEY, user)
        authorize_url = FLOW.step1_get_authorize_url()
        f = FlowModel(id=user, flow=FLOW)
        f.save()
        return HttpResponseRedirect(authorize_url)
    else:
        http = httplib2.Http()
        http = credential.authorize(http)
        service = build('content', 'v2', http=http)
        ids = get_account_ids(service)
        return render(
            request, 'index.html', {'ids':ids})


@login_required
def auth_return(request):
    user = request.user
    if not xsrfutil.validate_token(settings.SECRET_KEY, bytes(request.GET['state'], 'utf-8'), user):
        return HttpResponseBadRequest()
    credential = FLOW.step2_exchange(request.GET, http=None)
    storage = Storage(CredentialsModel, 'id', user, 'credential')
    storage.put(credential)
    return HttpResponseRedirect("/oauth2/")

At first, I was getting an error from the auth_return view that the string retuned by request.GET['state'] had no encoding, so I changed this:

if not xsrfutil.validate_token(settings.SECRET_KEY, request.GET['state'], user):

to this:

if not xsrfutil.validate_token(settings.SECRET_KEY, bytes(request.GET['state'], 'utf-8'), user):
        return HttpResponseBadRequest()

and the error was gone. However, I'm now getting the error:

'bytes' object has no attribute 'authorize'

from the index view. The exact line causing the exception is:

http = credential.authorize(http)

It seems like this is being caused by the earlier change I made. I'm new to using oauth2 and I have spent a lot of hours already trying to debug. Can anyone please point me in the right direction?

Thank you in advance.

Upvotes: 1

Views: 224

Answers (1)

Wedava
Wedava

Reputation: 1231

I finally found an answer.

It seems the django_orm module in oauth2client uses the 'to_python' function in the CredentialsField definition, which doesn't work and thus returns the Base64 data back.

TO solve this, you have to edit the oauth2client/django_orm source definition from:

class CredentialsField(models.Field):

to:

from django.utils.six import with_metaclass
class CredentialsField(with_metaclass(models.SubfieldBase, models.Field)):

This will allow it to return the Credentials object for both Python2 and Python3.

Make sure you delete the currently stored credentials object first since it is a string object and not a Credentials object.

Upvotes: 1

Related Questions