3

I'm trying to access Google API services through a headless Linux server using Oauth2. I read through all the answers on this post: How do I authorise an app (web or installed) without user intervention? but none of them showed how to use the refresh token to generate an access token in python. pinnoyyid had a javascript example (https://stackoverflow.com/a/19766913/15713034) that went something like this:

function get_access_token_using_saved_refresh_token() {
// from the oauth playgroundfunction get_access_token_using_saved_refresh_token() {
// from the oauth playground
const refresh_token = "1/0PvMAoF9GaJFqbNsLZQg-f9NXEljQclmRP4Gwfdo_0";
// from the API console
const client_id = "559798723558-amtjh114mvtpiqis80lkl3kdo4gfm5k.apps.googleusercontent.com";
// from the API console
const client_secret = "WnGC6KJ91H40mg6H9r1eF9L";
// from https://developers.google.com/identity/protocols/OAuth2WebServer#offline
const refresh_url = "https://www.googleapis.com/oauth2/v4/token";
let refresh_request = {
    body:`grant_type=refresh_token&client_id=${encodeURIComponent(client_id)}&client_secret=${encodeURIComponent(client_secret)}& refresh_token=${encodeURIComponent(refresh_token)}`;,
    method: "POST",
    headers: new Headers({
        'Content-Type': 'application/x-www-form-urlencoded'
    })
}

JavaScript isn't really my best language, but I could decipher they were sending a POST request to the google server. So I tried to recreate the request in Python with the requests package:

   import requests
   result = requests.post("https://www.googleapis.com/oauth2/v4/token", body={'grant_type':'refresh-token', 'client_id':client_id, 'client_secret':client_secret, 'refresh_token': refresh_token}, headers={'Content-Type': 'application/x-www-form-urlencoded'})
   

And when I look at result it shows it has a 200 status code (success) but when I try to examine the response, there's nothing easy to read and I can't parse the result in JSON to get the access token. The other approach I tried was to spin up a Flask server using Google's suggested code: https://developers.google.com/identity/protocols/oauth2/web-server#python_5 but that doesn't work either because when I try to return the credentials from one of the functions (object that contains the access code) that won't return JSON no matter what. I'd prefer the post request method since it is cleaner and uses less code. Thanks!

3 Answers3

2

In Python, one approach is to use requests-oauthlib to perform the Backend Application Flow. This is useful when you don't have a front-end to redirect someone to, in order to approve fetching a token.

gold_cy
  • 13,648
  • 3
  • 23
  • 45
  • Unfortunately, using both methods provided result in this issue when I get to oauth.fetch_token() argument: oauthlib.oauth2.rfc6749.errors.UnsupportedGrantTypeError: (unsupported_grant_type) Invalid grant_type: client_credentials – Cyrus Parvereshi Apr 21 '21 at 22:45
  • This is probably because Google's Oauth doesn't accept this client_credentials data type which is what HTTPBasicAuth() is. Do you know another way I can call .fetch_token()? Perhaps by using the 'body' or 'headers' parameters in fetch_token()? Reference: docs.authlib.org/en/latest/client/api.html#authlib.integrations.requests_client.OAuth2Session. – Cyrus Parvereshi Apr 21 '21 at 22:48
  • Here's a (somewhat unhelpful) related SO post: https://stackoverflow.com/questions/46751901/oauth2-unsupported-grant-type-invalid-grant-type-client-credentials – Cyrus Parvereshi Apr 21 '21 at 22:50
1

This website (https://community.atlassian.com/t5/Bitbucket-questions/Refresh-Tokens-using-Python-requests/qaq-p/1213162) says solution could be something like this:

   import requests
    auth = ("<consumer_id>", "<consumer_secret>")
    
    params = {
      "grant_type":"refresh_token",
      "refresh_token":"<your_refresh_token_here>"
    }
    
    url = "https://www.googleapis.com/oauth2/v4/token"
    
    ret = requests.post(url, auth=auth, data=params) #note data=params, not params=params
A.B.
  • 11
  • 3
1

Since none of the solutions above worked, I had to finally just give up and use a service account.