Bigquery google auth without browser prompt - python

i am accessing user data by connecting to bigquery via python with OAuth 2.0 method. But every time I make a query, it repeatedly asks for browser confirmation. How can I cancel this verification? When I set the launch_browser value to False, it requests confirmation from the terminal. Is there a different method I can use? I am using the same sample code found in the document https://cloud.google.com/bigquery/docs/authentication/end-user-installed
from google_auth_oauthlib import flow
from google.cloud import bigquery
launch_browser = True
appflow = flow.InstalledAppFlow.from_client_secrets_file(
"client_secrets.json", scopes=["https://www.googleapis.com/auth/bigquery"]
)
if launch_browser:
appflow.run_local_server()
else:
appflow.run_console()
credentials = appflow.credentials
project = 'user-project-id'
client = bigquery.Client(project=project, credentials=credentials)
query_string = """SELECT name, SUM(number) as total
FROM `bigquery-public-data.usa_names.usa_1910_current`
WHERE name = 'William'
GROUP BY name;
"""
query_job = client.query(query_string)
for row in query_job.result():
print("{}: {}".format(row["name"], row["total"]))

Storing the credentials in a file stops google from constantly requesting it, it only lasts for a little while though.
creds = None
# The file token.json 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.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# 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_console()
#creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
This is what I use to load credentials (I do mine through console as it is on Linux with no browser)
You may have to change some parts to fit your code but this is the general idea.

Related

Gmail-API with python

i'm building python GMAIL API for checking emails for 10 email accounts
but in google documentation not very useful.
this seems only support one account
https://github.com/suleenwong/Gmail-API-Python
If we check the default sample python quickstart This sample was designed to be single user but that can be changed.
The following section creates a token.json file when the user authorizes the application. The file will contain the access token and refresh token for the user who authorized the code.
If the file does not exist then the app will prompt the user to authorize it. If it does then the app will load the credentials from that file and run the code with the authorization of that user.
# The file token.json 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.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# 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.json', 'w') as token:
token.write(creds.to_json())
To add more users you can simply rename that file tokenUserOne.json, tokenUserTwo.json. Then set it up so that you can supply the file name you want your script to run on. You will only need to authorize each user once. As long as you have a token.json file for each user separated, your app can then be started using which ever token file you want, to access each users data.
https://developers.google.com/gmail/api/quickstart/python -this is the proper documentation everything you need is in here
aka (you also need a client_secet.json file but you will have to get yourself for the google cloud dashbord):
from __future__ import print_function
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
def main():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds = None
# The file token.json 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.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# 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.json', 'w') as token:
token.write(creds.to_json())
try:
# Call the Gmail API
service = build('gmail', 'v1', credentials=creds)
results = service.users().labels().list(userId='me').execute()
labels = results.get('labels', [])
if not labels:
print('No labels found.')
return
print('Labels:')
for label in labels:
print(label['name'])
except HttpError as error:
# TODO(developer) - Handle errors from gmail API.
print(f'An error occurred: {error}')
if __name__ == '__main__':
main()

python - how to authenticate against GmailAPI without user input

I have a small python script that collects some data and sends it in an email using the gmail api. My goal is to put this script on my raspberry, create a daily cronjob that calls it and forget about it. However, the way I have done my google authentication prevents me from automating it. Currently I have to authenticate using my browser(user needs to press the allow button), then I can use the credentials for a few days and then they expire and user input is required again. How can I make it authenticate once and then start refreshing its credentials automatically?
Current code:
def get_creds():
creds = None
if os.path.exists(os.path.join(dir,'token.json')):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
print("refreshing")
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
os.path.join(dir,'credentials.json'), SCOPES)
creds = flow.run_local_server(port=0)
with open(os.path.join(dir,'token.json'), 'w') as token:
token.write(creds.to_json())
return creds
You can use a service account instead of token. It doesn't expire.
from google.oauth2 import service_account
from googleapiclient.discovery import build
credentials = service_account.Credentials.from_service_account_file(
CREDENTIALS_JSON_PATH,
SCOPES
)
service = build('gmail', 'v1', credentials=credentials)
print(service.users().getProfile(userId='me').execute())
If you create Google Workspace service account you need to specify user email address
credentials = credentials.with_subject(USER_EMAIL)
As Daniel mentioned the problem was that my GoogleCLoud app was in test mode. I had to publish it first and then it started refreshing the token successfully without my help.
avoid auth token to expire

Unable to make multiple requests in a row using the google drive API

I have a problem with my google drive API.
I use this code to connect to my google account and get service :
from google.oauth2.credentials import Credentials
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
def getService():
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/drive']
"""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.json 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.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# 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(
'code_secret_client_XXX.apps.googleusercontent.com.json',
SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
service = build('drive', 'v3', credentials=creds)
return service
It works perfectly, but when I call 2 times for example :
result1 = GoogleDrive.service.files().list(
pageSize=1000, fields="nextPageToken, files(id, name)").execute()
result2 = GoogleDrive.service.about().get(
fields="storageQuota").execute()
I have this error :
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:2633)
According to the documentation the Drive API is built on top of Httplib2 which is not thread safe.
I use oauth2client which is deprecated, could that be the problem?
If I add a time.sleep(1) between my requests, it works.
if I remove one of the two requests, it works...
I don't understand how I can achieve that..
Thanks a lot
I think I found a solution :
def getCredentials():
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/drive']
"""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.json 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.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# 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(
'code_secret_client_XXX.apps.googleusercontent.com.json',
SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
return creds
def getService(creds):
service = build('drive', 'v3', credentials=creds)
return service
service = getService(credentials)
and :
http = google_auth_httplib2.AuthorizedHttp(credentials=GoogleDrive.credentials, http=httplib2.Http ())
result = GoogleDrive.service.about().get(
fields="storageQuota").execute(http=http)

PYTHON Login in with multiple account using Gmail api/imaplib

I'm currently working on an application requiring a gmail inbox. Currently i'm using the Gmail API with a credentials.json and a token.pickle and this is working fine although I want to login with other credentials each time the script is used. I'm quite new to this API and was wondering if it's possible to login with other credentials than the credentials used for the token.pickle.
Gmail API
To currently get a gmail inbox I use the following code:
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)
global service
service = build('gmail', 'v1', credentials=creds)
Imaplib
Another way I've tried to get a certain user's inbox is with the imaplib and email library since it lets you login with a certain email address and password. But to allow this to work a user needs to allow less secure apps to their google account which is a hassle for each user to enable that. The code I used for imaplib is the following code:
import imaplib, email
username = 'USERNAME'
password = 'PASSWORD'
imap_url = 'imap.gmail.com'
con = imaplib.IMAP4_SSL(imap_url)
con.login(username, password)
con.select('Inbox')
Question
My question is: Is it possible with the gmail api from google to login with multiple/other credentials to get the corresponding gmail inbox? If this is not possible and I have to use the Imaplib way, what are the steps I need to take so it doesn't require users to enable less secure apps?
Just change the .pickle file name. This code possibilite do this just changing the user variable. There will be different tokens to each account
def api_connection(user):
scopes = ['https://www.googleapis.com/auth/gmail.readonly']
creds = None
if os.path.exists(f'{user}.pickle'):
with open(f'{user}.pickle', 'rb') as token:
creds = pickle.load(token)
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)
with open(f'{user}.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('gmail', 'v1', credentials=creds)
return service

Any way to use Google Api without every-time authentication?

I tried to use the API on python in a autorun on a PC. But I can't because every time the program starts, it asks me about the authorization code.
This is my code:
client_secret_file = "client_secret.json"
flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(
client_secrets_file, scopes)
credentials = flow.run_console()
youtube = googleapiclient.discovery.build(
api_service_name, api_version, credentials=credentials)
Any help? Thanks
Becouse you are using the YouTube API you can not use a service account you will need to use Oauth2.
Oauth2 can return something called a refresh token, if you store this token your code can then access the refresh token the next time it runs and use the refresh token to request a new access token this way it will not need to ask you every time it runs to access your data.
# 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)
The only offical sample that includes refresh token that i know if is here Python quickstart you will need to alter it for YouTube but the auth code is really all you need just plug that int your code and you should be GTG
You can achieve this using Service Account.
https://googleapis.dev/python/google-api-core/latest/auth.html#service-accounts
Service account are technically pre authorized by the developer.
IF the API does not support Service account( in some cases) then you can try oauth2 where you have a consent for asking the owner of the account if you can access

Categories