djangopython-2.7django-socialauthgoogle-signinpython-social-auth

python-social-auth not getting correct Google OAuth2 details


I want to login a user using the python-social-auth functionality for Google Plus signin in Django. When logging in from my website, everything works fine and the correct details are added to the database.

However, I want to authenticate from my Android application as well. The user logs in in the application, which then sends the access token to the django API, which handles the login process in the following code, adapted from the documentation:

@csrf_exempt
@serengeti_api_request
@psa('social:complete')
def login_social_token(request, backend):
    # Ensure the token has been specified.
    token = request.META.get('HTTP_ACCESSTOKEN')
    if token is None:
        raise SerengetiApiRequestException('Access token is missing!')

    # Login the user for this session
    user = request.backend.do_auth(token)
    if user is None:
        raise SerengetiApiRequestException('Could not authenticate user!')

    login(request, user)

    # Store the email address if one has been specified (e.g. Twitter)
    email = request.META.get('HTTP_EMAIL')
    if email is not None:
        user.email = email
        user.save()

    # Prepare the parameters to be returned
    response = dict({
        'id': user.id,
        'first_name': user.first_name,
        'last_name': user.last_name,
        'api_key': request.session.session_key,
    })

    # Return a 200 status code to signal success.
    return HttpResponse(json.dumps(response, indent=4), status=200)

When logging in from the website, the social_auth_usersocialauth table contains:

id | provider      | uid       | extra_data
==========================================
10 | google-oauth2 | <myemail> | {"token_type": "Bearer", "access_token": "<token>", "expires": 3600}

However, when logging in from the application using the above function, the operation completes ok, but the entry in the table looks like this:

id | provider      | uid     | extra_data
=========================================
10 | google-oauth2 | <empty> | {"access_token": "", "expires": null}

Also, the auth_user table contains a username like eeed494412obfuscated48bc47dd9b instead of the Google Plus username and the email field is empty.

What am I doing wrong and how can I obtain the same functionality as I get on the website?

I would like to mention that I have implemented Facebook and Twitter authentication from the Android application, which call the above-mentioned function and store the correct details, only Google Plus is causing problems.


Solution

  • I finally figured it out myself. According to this article in the Android's Google Plus documentation, I also need to request the plus.profile.emails.read scope when making the request in the Android app. Once I added this, the python-social-auth code managed to store the email properly in the uid fields. This allows it to recognize the same user whether logging in from the website or the app, which is what I needed. Here's the scopes string I use:

    String scopes = "oauth2:" + Plus.SCOPE_PLUS_LOGIN + " https://www.googleapis.com/auth/plus.profile.emails.read";
    

    However, the extra_data field still contains the values I mentioned above. I believe this is due to needing to request offline access as well, which would allow Google Plus to pass the missing fields back to python-django-auth. More details can be found here.