I have headless software in Jetson Xavier. I am using Gmail API for sending mail. My code is working correctly in Laptop however GUI service is disabled in Jetson, browser cannot be opened. So, Authentication is failed when I try to use Gmail API in Jetson.
I have copied authenticated "token.pickle" to Jetson from laptop. It works fine that for a short time. Then, it wants an authentication again.
How can I solve this issue? How to block the browser to be opened for authentication in Jetson?
Thanks.
This part of code is for authentication:
class EmailSender:
def __init__(self):
# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/gmail.compose']
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:
creds_dir = os.path.dirname(os.path.abspath(__file__)) + '/credentials.json'
flow = InstalledAppFlow.from_client_secrets_file(
creds_dir, 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)
self.service = build('gmail', 'v1', credentials=creds)
Unfortunately, gmail(and most modern auth service) will not allow you to login automatically directly for safety reason. In order to ensure that a third party service not to steal your account, google will ask you as a human to type in your account and password and google will return a cookie, or token, to the service you try to login.
However, since you are working on your own project and I assume you know the program will not put your account at risk, you can use selenium to simulate a browser and type your account automatically. You may refer to this post to learn how to do it.
Related
I want to run this code https://developers.google.com/forms/api/quickstart/python that makes requests to google forms.
My question is how to get the credentials generate token.json file
from __future__ import print_function
from apiclient import discovery
from httplib2 import Http
from oauth2client import client, file, tools
SCOPES = "https://www.googleapis.com/auth/forms.body"
DISCOVERY_DOC = "https://forms.googleapis.com/$discovery/rest?version=v1"
store = file.Storage('token.json')
creds = None
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('client_secrets.json', SCOPES)
creds = tools.run_flow(flow, store)
form_service = discovery.build('forms', 'v1', http=creds.authorize(
Http()), discoveryServiceUrl=DISCOVERY_DOC, static_discovery=False)
The part most relevant to your question is here:
store = file.Storage('token.json')
creds = None
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('client_secrets.json', SCOPES)
creds = tools.run_flow(flow, store)
Trying to put it simply:
The store variable defines a local file where the token will be located, in this case it's token.json.
Then the flow object tries to look for a file called client_secrets.json where your credentials should be located. There's an explanation on how to generate these credentials from the Cloud Console here. Once you have this file you can just place it in the same folder as your quickstart.py. Make sure that the name in the method matches the name in the directory.
Then tools.run_flow(flow, store) will use the credentials in the flow object (which are in your client_secrets.json file) to run a temporary webserver and open a page in your browser where you have to go through the OAuth flow to authorize the app. Once this flow is done, the resulting token will be written to the token.json file which you defined in the store variable. The creds variable can then be used to run API calls.
For some reason the Forms quickstart you linked has a few differences from others as pointed out by furas. The difference in the Drive API sample is that it checks for the token.json file first so if it exists it won't go through the OAuth flow. On the other hand the Forms quickstart seems like it would go through the flow every time without checking, and it also uses a different method to run the flow. This is the part in the authorization that changes:
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())
I don't know if there's a technical reason for this discrepancy in the documentation or if it's just an oversight/outdated way to do it, but you can just replace the top code block with the one at the bottom and it should work either way, but the second is preferable. Just keep in mind that you will need the credentials.json file in the same location as the script file.
Sources:
Create authorization credentials
oauth2client.tools module
Flow module
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
I'm trying to build a Google Classroom extension that gives the user control over when to receive "Work Due Soon" notifications. However, when the token refreshes, I get this error: "raise exceptions.RefreshError(google.auth.exceptions.RefreshError: Not all requested scopes were granted by the authorization server, missing scopes https://www.googleapis.com/auth/classroom.coursework.me.readonly. "
The code being used is straight from the google authorization page for google classroom
SCOPES = ['https://www.googleapis.com/auth/classroom.courses.readonly', 'https://www.googleapis.com/auth/classroom.coursework.me.readonly']
def main():
"""Shows basic usage of the Classroom API.
Prints the names of the first 10 courses 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(
'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())
As you can see, the scope in the error, is already in my list of scopes for the project. The only way I've found to get around this is to delete the token file, and sign-in every time the token expires. I've checked the classroom api documentation and stack overflow but I couldn't find a solution. Any help will be appreciated.
I'm trying to build a simple python script to access gmail's API and organize certain email messages inmy inbox into a csv file.
I see in the below documentation that accessing the messages is done using the user's (mine in this case) email address.
messages.list
I'm running into difficulty accessing the API. I'm getting the below error:
"Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project."
I was hoping to build a light weight script not a web application. Does anyone know if there is a way I can authenticate my own email address in a script?
PS: I suppose I could use selenium to automatically sign in but I was wondering if there was a way to do this using gmail's API.
You need to understand that the data you are trying to access is private user data. This is data owned by a user that being you, which means your application need to be "authorized" by the user "you" to access their data.
We do this with a method called Oauth2, it will allow your application to request consent for access to read the users emails in this case.
In order to use Oauth2 you must first register your applcation on Google Developer console and set up a few things, this will identify your application to Google.
All of this is explained in the Python quick-start for gmail. Once you have that working you should be able to change the code to use message.list instead of labels.list.
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/gmail.readonly']
def main():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
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('gmail', 'v1', credentials=creds)
# Call the Gmail API
results = service.users().labels().list(userId='me').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()
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