Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the Python Request Library to get Google Oauth2 tokens

I've spent hours trying to troubleshoot how to get oauth2 tokens using the python request library. What am I doing wrong?

  r=requests.post("https://accounts.google.com/o/oauth2/token",
                            headers={
                                'content-type':'application/x-www-form-urlencoded'},
                            params={
                                'code':request.GET['code'],
                    'client_id':'11111111111.apps.googleusercontent.com',
                                'client_secret':'my secert',
                                'redirect_uri':'http://localhost/etc'
                                'grant_type':'authorization_code'})
like image 984
tjb Avatar asked Aug 02 '13 10:08

tjb


2 Answers

The data for the request must be sent in the body NOT IN the query string

change params= to data= in your code.

See this discussion for details: https://groups.google.com/forum/#!topic/oauth2-dev/ahP0cz2ao0o

like image 148
tjb Avatar answered Oct 13 '22 12:10

tjb


This is a very late answer, but might be useful to some.

I have got Google OAuth2 flow working nicely with requests in this simple class

from requests.adapters import HTTPAdapter
from requests_oauthlib import OAuth2Session
from urllib3.util.retry import Retry
import os

from yaml import load, dump, YAMLError

try:
    from yaml import CLoader as Loader, CDumper as Dumper
except ImportError:
    from yaml import Loader, Dumper


# OAuth endpoints given in the Google API documentation
authorization_base_url = "https://accounts.google.com/o/oauth2/v2/auth"
token_uri = "https://www.googleapis.com/oauth2/v4/token"

'''
Defines a very simple class to handle google api authorization flow
for the requests library. Includes saving the token and automatic
token refresh.
giles 2018
'''


class Authorize:
    def __init__(self, scope, token_file, secrets_file):
        self.scope = scope
        self.token_file = token_file
        self.session = None
        self.token = None
        try:
            with open(secrets_file, 'r') as stream:
                all_yaml = load(stream, Loader=Loader)
            secrets = all_yaml['installed']
            self.client_id = secrets['client_id']
            self.client_secret = secrets['client_secret']
            self.redirect_uri = secrets['redirect_uris'][0]
            self.token_uri = secrets['token_uri']
            self.extra = {
                'client_id': self.client_id,
                'client_secret': self.client_secret}

        except (YAMLError, IOError):
            print('missing or bad secrets file: {}'.format(secrets_file))
            exit(1)

    def load_token(self):
        try:
            with open(self.token_file, 'r') as stream:
                token = load(stream, Loader=Loader)
        except (YAMLError, IOError):
            return None
        return token

    def save_token(self, token):
        with open(self.token_file, 'w') as stream:
            dump(token, stream, Dumper=Dumper)
        os.chmod(self.token_file, 0o600)

    def authorize(self):
        token = self.load_token()

        if token:
            # force refresh on load token.expires_in = -30
            #  todo this is no longer in the token ??
            #   how to force update?
            self.session = OAuth2Session(self.client_id, token=token,
                                         auto_refresh_url=self.token_uri,
                                         auto_refresh_kwargs=self.extra,
                                         token_updater=self.save_token)
        else:
            print(self.scope)
            self.session = OAuth2Session(self.client_id, scope=self.scope,
                                         redirect_uri=self.redirect_uri,
                                         auto_refresh_url=self.token_uri,
                                         auto_refresh_kwargs=self.extra,
                                         token_updater=self.save_token)

            # Redirect user to Google for authorization
            authorization_url, _ = self.session.authorization_url(
                authorization_base_url,
                access_type="offline",
                prompt="select_account")
            print('Please go here and authorize,', authorization_url)

            # Get the authorization verifier code from the callback url
            response_code = input('Paste the response token here:')

            # Fetch the access token
            self.token = self.session.fetch_token(
                self.token_uri, client_secret=self.client_secret,
                code=response_code)
            self.save_token(self.token)

        # note this does retries on POST as well
        # CAUTION - this might not be desirable for all applications
        retries = Retry(total=5,
                        backoff_factor=0.1,
                        status_forcelist=[500, 502, 503, 504],
                        method_whitelist=frozenset(['GET', 'POST']),
                        raise_on_status=False)
        self.session.mount('https://', HTTPAdapter(max_retries=retries))
like image 32
Giles Knap Avatar answered Oct 13 '22 12:10

Giles Knap