pythonoauthgoogle-apigoogle-oauthrauth

Google OAuth token request returns "invalid_client": "Unauthorized"


Trying to get OAuth2 Google login working, this is the raw request that my app makes:

Method: POST

URL: https://www.googleapis.com/oauth2/v3/token

Headers: Content-Type: application/x-www-form-urlencoded

Values:

client_id: XXX-0123456789abcdef0123456789abcdef.apps.googleusercontent.com

client_secret: A1b2C3d4E5f6G7h8I9j0K1l2M

code: 1/A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8S9t0U1v

grant_type: authorization_code

redirect_uri: http://localhost:5000/callback/google/

And this is the response:

Status: 401 Unauthorized

Body:

{
    "error": "invalid_client",
    "error_description": "Unauthorized"
}

Have verified that this is the exact request / response that my app is making (a Python app using Flask and rauth), and have verified that I can reproduce the exact same request / response using Postman.

Per instructions in other threads, I have done all of the following in the Google APIs console:

No matter what I do, still getting the same response of "invalid_client": "Unauthorized".

Help with this would be appreciated. Am trying to set up OAuth2-powered "Log in with X" functionality in my app, have gotten Facebook and Twitter working without issues, would like to get Google working too, but if I can't resolve this then I'm afraid I'll have to ditch Google auth.


Solution

  • Invalid client means that the client id or the client secret that you are using are not valid. They must be the ones you have downloaded from Google Developer console.

    Tip: You might want to consider using the Google python client library it does all the heavy lifting for you.

    from __future__ import print_function
    import pickle
    import os.path
    from googleapiclient.discovery import build
    from google_auth_oauthlib.flow import InstalledAppFlow
    from google.auth.transport.requests import Request
    
    # If modifying these scopes, delete the file token.pickle.
    SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']
    
    def main():
        """Shows basic usage of the Drive v3 API.
        Prints the names and ids of the first 10 files the user has access to.
        """
        creds = None
        # The file token.pickle stores the user's access and refresh tokens, and is
        # created automatically when the authorization flow completes for the first
        # time.
        if os.path.exists('token.pickle'):
            with open('token.pickle', 'rb') as token:
                creds = pickle.load(token)
        # If there are no (valid) credentials available, let the user log in.
        if not creds or not creds.valid:
            if creds and creds.expired and creds.refresh_token:
                creds.refresh(Request())
            else:
                flow = InstalledAppFlow.from_client_secrets_file(
                    'credentials.json', SCOPES)
                creds = flow.run_local_server(port=0)
            # Save the credentials for the next run
            with open('token.pickle', 'wb') as token:
                pickle.dump(creds, token)
    
        service = build('drive', 'v3', credentials=creds)
    
        # Call the Drive v3 API
        results = service.files().list(
            pageSize=10, fields="nextPageToken, files(id, name)").execute()
        items = results.get('files', [])
    
        if not items:
            print('No files found.')
        else:
            print('Files:')
            for item in items:
                print(u'{0} ({1})'.format(item['name'], item['id']))
    
    if __name__ == '__main__':
        main()