Handle Google OAuth 2.0 API to use AndroidPublisher from a WebServer (Python)

The scope of this article

🕵🏾‍ Why ?

An easy access to information. And above all, by restricting the scope of data that we are allowed to use we enhance the:

‍‍🧙🏻 ‍How ?

Few steps :

👮🏼 ‍Create Google Credentials

Step 0 and Step 1: Go here

Step 0 Step 1

Step 2: Then Click on Create OAuth Client And View in Google Developers Console

Step 2

Step 3: Now by editing your ID Clients OAuth 2.0 line you can get your client_id and your client_secret

Step 3

Step 4: We recommend to change the name in order to be sure to know what this client is used for.

Step 4

WARNING If you want to use the Google AndroidPublisher API from an app that isn’t associated to your project (here on the picture step 2, it is called Google Play Android Developer) you will need the app owner to do the same step and provide you with his client_id and client_secret to continue. Otherwise you will get an error from google: The project id used to call the Google Play Developer API has not been linked in the Google Play Developer Console.

👩🏽‍💻 Front

Step 1: Ask for permission and get a temp token to exchange

For this operation you will need the previous client ID that we’ll call GOOGLE_OAUTH_CLIENT_ID. And we have to set some variables:

Now you need in your front a way (for instance a button) to send to this adapted url:

https://accounts.google.com/o/oauth2/v2/auth?
  &scope=${SCOPE}
  &access_type=${ACCESS_TYPE}
  &include_granted_scopes=${INCLUDE_GRANTED_SCOPES}
  &state=${STATE}
  &redirect_uri=${REDIRECT_URI}
  &response_type=${RESPONSE_TYPE}
  &client_id=${GOOGLE_OAUTH_CLIENT_ID}

Step 3: handle the return authorization code

Once your user finished the accept permissions process. It will be redirected to this address

${REDIRECT_URI}?state=${STATE}&code=${GOOGLE_CODE_TOKEN}&scope=${SCOPE}

Now your are back in your front. (OPTIONAL) Check the state in the URL and the state in your user session 1- Now you get your GOOGLE_CODE_TOKEN 2- Send it to your backend.

WARNING You also have to handle the case when the user refuse those permissions.

🤖 Back

Setup if you want to use the Python API

You will need those python packages

google-api-python-client
google-auth
google-auth-httplib2
oauth2client
google-auth-oauthlib
requests
pyOpenSSL
ndg-httpsclient
pyasn1

Step 1: Ask for the access_token and refresh_token

With the GOOGLE_CODE_TOKEN you can now ask for the real token.

HTTP POST Request

https://accounts.google.com/o/oauth2/token?
  grant_type=authorization_code
  &code=${GOOGLE_CODE_TOKEN}
  &client_id=${client_id}
  &client_secret=${client_secret}
  &redirect_uri=${REDIRECT_URI}

or with python

client_config = {
    "web": {
        "client_id": ${client_id},
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://accounts.google.com/o/oauth2/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_secret": ${client_secret},
        "redirect_uris": [
            ...YOUR_URIS
        ],
        "javascript_origins": [
            ...YOUR_ORIGINS
        ]
    }
}
session, client_config = (
    google_auth_oauthlib.helpers.session_from_client_config(
        client_config, scopes=cls.SCOPES, redirect_uri=cls.REDIRECT_URI))
flow = google_auth_oauthlib.flow.Flow.from_client_config(
    client_config,
    scopes=cls.SCOPES,
    redirect_uri=cls.REDIRECT_URI
)
# Or you could directly download the client_secret.json from google and use
# flow = google_auth_oauthlib.flow.Flow.from_client_secret(
#    client_secret_path,
#    scopes=cls.SCOPES,
#    redirect_uri=cls.REDIRECT_URI
#)

flow.fetch_token(code=temp_token)

# Object with attribute token, refresh_token, token_uri, client_id, client_secret, scopes
credentials = flow.credentials

print(credentials.token) 
print(credentials.refresh_token)

WARNING if you have already ask for a token you won’t be able to ask for a new one and you will see a “(invalid_grant) Bad Request” So you will have to send your users to https://myaccount.google.com/permissions and ask them to remove access to your app.

I haven’t found yet a way for the application to remove the granted access so if you have any idea please share :)

Step 2: Test the android publisher api

Now we will try to get the list of the reviews of the app linked to this project with the package name PACKAGE_NAME. HTTP GET

https://www.googleapis.com/androidpublisher/v3/applications/${PACKAGE_NAME}/reviews

Don’t forget to set the header Authorization: Bearer ${YOUR_ACCESS_TOKEN}

Or you could use the python api

token_uri = "https://oauth2.googleapis.com/token"
credentials =  google.oauth2.credentials.Credentials(token=${YOUR_ACCESS_TOKEN},
                                                     refresh_token=${YOUR_REFRESH_TOKEN},
                                                     token_uri=token_uri,
                                                     client_id=${client_id},
                                                     client_secret=${client_secret},
                                                     scopes=${SCOPES}
                                                     )
service = build('androidpublisher', 'v3', credentials=credentials, cache_discovery=False)
print(service.reviews().list(packageName=${PACKAGE_NAME}))

Step 3: Token refresh

You could do it by an Http POST Request like this

https://oauth2.googleapis.com/token?
  grant_type=refresh_token
  &client_id=${GOOGLE_OAUTH_CLIENT_ID}
  &client_secret=${GOOGLE_OAUTH_CLIENT_SECRET}
  &refresh_token=${YOUR_REFRESH_TOKEN}

Or you could use the python api

import httplib2
from oauth2client import client, GOOGLE_REVOKE_URI, GOOGLE_TOKEN_URI

credentials = client.OAuth2Credentials(
    access_token=None,  # set access_token to None since we use a refresh token
    client_id=self.client_id,
    client_secret=self.client_secret,
    refresh_token=self.refresh_token,
    token_expiry=None,
    token_uri=GOOGLE_TOKEN_URI,
    user_agent=None,
    revoke_uri=GOOGLE_REVOKE_URI)
    
credentials.refresh(httplib2.Http())  # refresh the access token
return credentials.access_token, credentials.refresh_token

🌜Final point

Don’t forget to write a process to revoke this token in order to be compliant to GDPR.

And follow us on Medium

Sources

Google API for python

OAuth 2 Simplified by Aaron Parecki Well explained and tackle every kind of implementation of OAuth

OAuth 2 for WebServer by Google

Google Playground to test and see all scope available

Really useful diagram

x

COOKIE NOTICE

This website uses cookies for marketing, analytics, to enhance user experience. More info OK