Invalid response 405 when using airflow GoogleBaseHook in python - python

I am running airflow in docker. I create an airflow Google Cloud connection through web server GUI on my localhost:8080. In python code, I want to read data in Gsheet to with GoogleBaseHook as:
import json
from googleapiclient.discovery import build
from airflow.providers.google.common.hooks.base_google import GoogleBaseHook
from oauth2client.service_account import ServiceAccountCredentials
gcp_hook = GoogleBaseHook(gcp_conn_id="spx-service-account")
cred_dict = json.loads(gcp_hook._get_field('keyfile_dict'))
SCOPES = ['https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_dict(cred_dict, scopes=SCOPES)
service = build('sheets', 'v4', credentials=creds, cache_discovery=False)
sheet = service.spreadsheets()
result = sheet.values().get(spreadsheetId="1yN3atY6NG7PfY8yNcNAiVqURra8WtQJWCKXc-ccymk0", range="Sheet1!A1:B4").execute()['values']
But executing the code above shows Failed to retrieve access token. 405 Not Allowed
Error:
Does anyone know what causes this error and how I can solve it? Thank you.

Oops, it ends up to be something wrong with my keyfile JSON. I have no idea why those token_uri is encoded when I downloaded it from my Gmail (tech team sent it to us via email) and opened it with my windows laptop. If your credential is correct, the code below should work:
import json
from googleapiclient.discovery import build
from airflow.providers.google.common.hooks.base_google import GoogleBaseHook
from oauth2client.service_account import ServiceAccountCredentials
gcp_hook = GoogleBaseHook(gcp_conn_id="spx-service-account")
cred_dict = json.loads(gcp_hook._get_field('keyfile_dict'))
SCOPES = ['https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_dict(cred_dict, scopes=SCOPES)
service = build('sheets', 'v4', credentials=creds, cache_discovery=False)
sheet = service.spreadsheets()
result = sheet.values().get(spreadsheetId="1yN3atY6NG7PfY8yNcNAiVqURra8WtQJWCKXc-ccymk0", range="Sheet1!A1:B4").execute()['values']

Related

Retrieving google sheet values with google sheet api on company restricted spreadsheet

I want to be able to read a spreadsheet, that has been shared with me, inside the company I work.
I have tried adapting the script from this link.
This is the code I use:
from apiclient import discovery
from oauth2client.service_account import ServiceAccountCredentials
import httplib2
scope = [
'https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive'
]
SERVICE_ACCOUNT_FILE = "gsheetread-293005-d7e75122e4c7.json"
credentials = ServiceAccountCredentials.from_json_keyfile_name(
SERVICE_ACCOUNT_FILE, scopes=scope)
# Use the create_delegated() method and authorize the delegated credentials
delegated_credentials = credentials.create_delegated('myemail#company.com')
delegated_http = delegated_credentials.authorize(httplib2.Http())
google_sheet = discovery.build('spreadsheet_id', 'v3', http=delegated_http)
I get an error:
oauth2client.client.HttpAccessTokenRefreshError: unauthorized_client: Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested.
The error you're getting means you didn't add some or all of the specified scopes (https://www.googleapis.com/auth/spreadsheets,
https://www.googleapis.com/auth/drive) when granting domain-wide authority to your service account. Please follow these steps:
In step 5, you have to add both https://www.googleapis.com/auth/spreadsheets,
https://www.googleapis.com/auth/drive (actually, you only need to add one, if you're just accessing a spreadsheet, but you should remove the other one from your code).
Additional notes:
The library you're using, oauth2client, is deprecated. Use google-auth instead, which doesn't rely on httplib2.
You're not using a valid service name (spreadsheet_id). If you want to use Sheets API, the service name should be sheets.
Sheets API V3 is deprecated and will be shut down in January 2021. Use V4 instead.
As I mentioned before, there's no need to use the drive scope if you're accessing a spreadsheet. spreadsheets is enough.
Code snippet (using non-deprecated library):
from googleapiclient.discovery import build
from google.oauth2 import service_account
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
SERVICE_ACCOUNT_FILE = "gsheetread-293005-d7e75122e4c7.json"
creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
delegated_credentials = creds.with_subject('myemail#company.com')
service = build('sheets', 'v4', credentials=delegated_credentials)
spreadsheet = service.spreadsheets().get(spreadsheetId="YOUR_SPREADSHEET_ID").execute()
print(spreadsheet)

Obtain a service account credentials within a Cloud Functions to call a google service outside GCP

My scenario: I need to call the Google DBM API using google-api-python-client from a Cloud Function using a service account.
Update
Here the sample code I trying to run:
import google.auth
from googleapiclient.discovery import build
from google.auth.transport import requests
API_NAME = 'doubleclickbidmanager'
API_VERSION = 'v1.1'
SCOPES = ['https://www.googleapis.com/auth/doubleclickbidmanager']
credentials, project_id = google.auth.default(scopes=SCOPES)
print(credentials.service_account_email)
# prints "default"
credentials.refresh(requests.Request())
print(credentials.service_account_email)
# prints "[service-account]#[project].iam.gserviceaccount.com"
service = build(API_NAME, API_VERSION, credentials=credentials)
service.queries().listqueries().execute()
# local: return the queries
# in CF: Encountered 403 Forbidden with reason "insufficientPermissions"
When I run locally setting the environment variable GOOGLE_APPLICATION_CREDENTIALS=keyfile.json works fine.
But when running in the Cloud Function I got the 403 error.
The keyfile.json use the same service account [service-account]#[project].iam.gserviceaccount.com setted in the Cloud Function.
You have to force the library to generate a token to force it to fulfill all its fields. For this, simply call a retry, like this
import google.auth
credentials, project_id = google.auth.default(scopes=SCOPES)
from google.auth.transport import requests
credentials.refresh(requests.Request())
print(credentials._service_account_email)
build(API_NAME, API_VERSION, credentials=credentials)

How to properly connect to Google Spreadsheets API?

I want to connect to the Google Spreadsheets API with Python.
So I do:
import gspread
from oauth2client.service_account import ServiceAccountCredentials
scope=['https://www.googleapis.com/auth/spreadsheets',
'https://wwww.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name('cred.json', scope)
gc = gspread.authorize(credentials)
wks = gc.open('datatest').Sheet1
print(wks.get_all_records)
But I get this error
HttpAccessTokenRefreshError: invalid_scope: https://www.googleapis.com/auth/spreadsheets is not a valid audience string.
How can I use Google-auth instead of gspread with this data?
you input 4w !!!!
X 'https://wwww.googleapis.com/auth/drive'
O 'https://www.googleapis.com/auth/drive'
import gspread
from oauth2client.service_account import ServiceAccountCredentials
scope = ['https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name('CredentialsFile.json', scope)
ss_app = gspread.authorize(credentials=credentials) # make sure your Google Sheets API is enabled
sht = ss_app.open('sheet_name_xxxx') # In your spreadsheet, click the Share button and paste the client email as same as CredentialsFile.json.client_email, and make sure your Google Drive API is enabled
wks = sht.worksheet('worksheet_name_xxxx')
print(wks.acell('A1').value)
hope that it helps.

Python Google Drive Authentification - Error: admin_policy_enforced

I am using python to upload or download files on Google Drive. This is the most important part of my code:
from httplib2 import Http
from oauth2client import file, client, tools
from apiclient.http import MediaFileUpload
from apiclient import errors
import io
from apiclient.http import MediaIoBaseDownload
from apiclient import errors
import os
import csv
#####################################
try :
import argparse
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
flags = None
SCOPES = 'https://www.googleapis.com/auth/drive.file'
store = file.Storage('storage.json')
creds = store.get()
if not creds or creds.invalid:
print("Create new data storage file ...")
flow = client.flow_from_clientsecrets('client_secrets.json', SCOPES)
flow.redirect_uri = client.OOB_CALLBACK_URN
authorize_url = flow.step1_get_authorize_url()
creds = tools.run_flow(flow, store, flags) \
if flags else tools.run(flow, store)
print ("Storage")
DRIVE = build('drive', 'v2', http=creds.authorize(Http()))
The python-script worked fine for 2 month. But since yesterday I get this error if I start my script:
400. That’s an error.
Error: admin_policy_enforced
Company security policies do not allow this app to connect to your Company account data. Please contact your local helpdesk for any support.
Request Details
client_id=XXXYYYZZZ.apps.googleusercontent.com
redirect_uri=urn:ietf:wg:oauth:2.0:oob
scope=https://www.googleapis.com/auth/drive.file
access_type=offline
response_type=code
My admin rights have not been changing till now. Do someone have an idea?

GMAIL API: <HttpError 400 when requesting https://www.googleapis.com/gmail/v1/users/myemail%40gmail.com/labels?alt=json returned "Bad Request">

I am trying to write a python program that will access my gmail account through the gmail API using account services. I followed all the steps in the Using OAuth 2.0 for Server to Server Applications
here is my code:
from __future__ import print_function
import httplib2
import os
from apiclient.discovery import build
from httplib2 import Http
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
from oauth2client.service_account import ServiceAccountCredentials
try:
import argparse
flags = argparse.ArgumentParser(parents=[ tools.argparser]).parse_args()
except ImportError:
flags = None
def main():
SCOPES = ['https://www.googleapis.com/auth/gmail.modify']
APPLICATION_NAME = 'Gmail Application'
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'MyKeyFile.json', scopes=SCOPES)
http_auth = credentials.authorize(Http())
service = build('gmail', 'v1', http=http_auth)
results = service.users().labels().list(userId='myemail#gmail.com').execute()
labels = results.get('labels', [])
if not labels:
print('No labels found.')
else:
print('Labels:')
for label in labels:
print(label['name'])
if __name__ == '__main__':
main()
When I run this i get a an error 400 Bad Request.
Anyone encountered this issue. I have been changing things around foro a couple of days now and nothing has worked: I used the service ID instead of my email, I used p12 credentials api, created new projects and new account services with new keys... you name it. I'm hitting a wall. Can anyone help?
Thanks
You should to Enable your API on Dashboard in your API Manager menu here
Then, choose you interested in API
Finally, you'll see something like this

Categories