Inserting Custom Dimensions using Google Analytics API v3 - python

I am using Google Analytics API to insert a custom dimension. I have set up the required Oauth2 credentials and obtained an access token and a refresh token. However, when I called my function that inserts a custom dimension to a specified Account and webProperty in Google Analytics, I get an error message that reads as follows:
<HttpError 403 when requesting: URL
returned "Request had insufficient authentication scopes.". Details: "[{'message': 'Insufficient Permission', 'domain': 'global', 'reason': 'insufficientPermissions'}]">
I opened the URL and got the following error message
Error message
Using the same code, I am able to fetch all accounts and webProperties in Google Analytics but apparently it can neither insert nor update custom dimensions and I don't know what I am missing in my code.
Here is my code:
from apiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
from googleapiclient.errors import HttpError
import os
from google.oauth2.credentials import Credentials
from google.auth.transport.requests import Request
scope = ['https://www.googleapis.com/auth/analytics']
def get_service():
"""
authorises user to access GA resources and builds a service object
"""
creds = None
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', scopes=scope)
# 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(
'client_secrets.json', scopes=scope)
creds = flow.run_local_server(port=80)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
# build a service object
service = build('analytics', 'v3', credentials=creds)
return service
def insert_customDimension(service):
# Inserts a custom Dimension at a specific index.
try:
service.management().customDimensions().insert(
accountId=ACCOUNT_ID,
webPropertyId=WEB_PROPERTY_ID,
body={'name': 'free to use',
'scope': 'HIT',
'active': False,
'index': 200
}
).execute()
except HttpError as error:
print(error)
except TypeError as er:
print(er)
def main():
# Authenticate and construct service.
service = get_service()
insert_customDimension(service)
if __name__ == '__main__':
main()
I would like to understand what am I doing wrong or what do I need to change in my code? I have deleted the token.json file and ran the code but I was unable to complete the authorization flow and not token.json was automatically created. I manually obtained the refresh and access token and created the file. I have admin privileges to the Google Analytics account I am trying to insert custom dimensions into.

Related

Delegation denied using Google Gmail API Python SDK

Intoduction
I am an administrator of Google Admin Workspace. What I want to do, is to get list of the user's Gmail labels.
Code
Here is how the code looks like:
def show_lables(email_from, service):
results = service.users().labels().list(userId=email_from).execute()
labels = results.get('labels', [])
if not labels:
print('No labels found.')
return
print('Labels:')
for label in labels:
print(label['name'])
Here is the problem, I can get my own Gmail labels, but cannot get labels of other user (within one organization, same domain name).
So, I have read about Google Service Account, created and configured one. It works just find, because I tested it with other Google Services, but here is the code:
def init_services(client_secret_file, api_name, api_version, delegated_user=None):
creds = None
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES[api_name])
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(client_secret_file, SCOPES[api_name])
creds = flow.run_local_server()
with open('token.json', 'w') as token:
token.write(creds.to_json())
if delegated_user is not None:
credentials = service_account.Credentials.from_service_account_file(
'service.json', scopes=SCOPES[api_name])
creds = credentials.with_subject(delegated_user)
try:
service = build(api_name, api_version, credentials=creds)
return service
except Exception as e:
print(f'An error occurred: {e}')
Issue
Basically, when I want to create service, I just call this function, and when I want to delegate credentials, I just add delegated_user email.
service = init_services(file_name, 'gmail', 'v1','admin#company.com')
show_lables('someuser#company.com', 'admin#company.com', service)
So, here is the issue - when I create service with delegated user and put my email as delegated user email - admin#company.com, and try to get labels of emails of other user (someuser#company.com) I get next error:
<HttpError 403 when requesting
https://gmail.googleapis.com/gmail/v1/users/someuser%40company.com/labels?alt=json
returned "Delegation denied for admin#company.com". Details: "[{'message':
'Delegation denied for admin#company.com', 'domain': 'global', 'reason':
'forbidden'}]">
As I said, I have configured Google Service Account, I have proper scope - https://mail.google.com/, but I still have no idea what is wrong.

problems with my Python code connecting with google docs api

I'm coding a Python app to automatize invoices via a google docs API but I'm having errors with the code and I don't know how to solve it
# [START docs_quickstart]
from __future__ import print_function
import os.path
import gspread
from oauth2client.service_account import ServiceAccountCredentials
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/documents.readonly','https://www.googleapis.com/auth/documents','https://www.googleapis.com/auth/drive.file','https://www.googleapis.com/auth/drive','https://www.googleapis.com/auth/drive.readonly']
def main():
"""Shows basic usage of the Docs API.
Prints the title of a sample document.
"""
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:
service = build('docs', 'v1', credentials=creds)
title = 'My Document'
body = {
'title': title
}
document = service.documents().create(body=body).execute()
print('Created document with title: {0}'.format(
document.get('title')))
except HttpError as err:
print(err)
if __name__ == '__main__':
main()
# [END docs_quickstart]
and this is the error code that I'm having
PS D:\Universidad\Proyectos de Programacion Propia\python\googledocsinvoice.restapi> python quickstart.py
<HttpError 403 when requesting https://docs.googleapis.com/v1/documents?alt=json returned "Request had insufficient authentication scopes.". Details: "[{'#type': 'type.googleapis.com/google.rpc.ErrorInfo', 'reason': 'ACCESS_TOKEN_SCOPE_INSUFFICIENT', 'domain': 'googleapis.com', 'metadata': {'service': 'docs.googleapis.com', 'method': 'google.apps.docs.v1.DocumentsService.CreateDocument'}}]">
if you know some guide or complete tutorial to Automate Document Creation with the Google Docs API like invoices and replace encapsulation values like {{productID}} I will be very grateful
I saw the Automate document creation of google channel but it wasn't very helpful https://youtu.be/-dX-fWb3ogE
Best Regards
Make sure you also enable the Docs API in your Developers Console.
Delete the credential file ~/.credentials.json and token.json (if you ran the code before
Change the scope variable used for reading docs
var SCOPES = ['https://www.googleapis.com/auth/documents.readonly'];
to
var SCOPES = ['https://www.googleapis.com/auth/documents'];
Check more info on https://developers.google.com/docs/api/reference/rest/v1/documents/create#authorization-scopes and https://developers.google.com/docs/api/how-tos/authorizing
After the execution of code, API will authenticate again and then the issue should be resolved.

Authorize google api requests to list users

I want to get list of users google api but face an issue
My steps are:
Created Service account with domain wide delegation and listed scopes (same as in the script)
Downloaded json file with private key
On execution of the next script
import google.auth
import google.auth.transport.requests
from google.oauth2 import service_account
import requests
credentials = service_account.Credentials.from_service_account_file('key.json', scopes=[
'https://www.googleapis.com/auth/admin.directory.user',
'https://www.googleapis.com/auth/admin.directory.group',
'https://www.googleapis.com/auth/admin.directory.group.member',
'https://www.googleapis.com/auth/admin.directory.user.security',
'https://www.googleapis.com/auth/admin.directory.user.readonly'
])
auth_req = google.auth.transport.requests.Request()
refresh = credentials.refresh(auth_req)
response = requests.get('https://www.googleapis.com/admin/directory/v1/users?domain=domain.com',
headers={'Authorization': f'Bearer {credentials.token}'})
Response is:
{
"error": {
"code": 403,
"message": "Not Authorized to access this resource/api",
"errors": [
{
"message": "Not Authorized to access this resource/api",
"domain": "global",
"reason": "forbidden"
}
]
}
}
I ended up with the next solution
console.cloud.google.com => APIs & Services > Credentials
Create Credentials > OAuth Client ID > Desktop APp
Saved key as 'credentials.json'
The rest id described here
from __future__ import print_function
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/admin.directory.user']
#
def main():
"""Shows basic usage of the Admin SDK Directory API.
Prints the emails and names of the first 10 users in the domain.
"""
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:
print('Refreshing token')
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'python_admin.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('admin', 'directory_v1', credentials=creds)
# Call the Admin SDK Directory API
print('Getting the first 10 users in the domain')
service_users = service.users()
results = service_users.list(customer='my_customer', maxResults=10, orderBy='email').execute()
users = results.get('users', [])
service_users.insert()
if not users:
print('No users in the domain.')
else:
print('Users:')
for user in users:
print(u'{0} ({1})'.format(user['primaryEmail'],
user['name']['fullName']))
if __name__ == '__main__':
main()
For the first time I had to authorize request in the browser, after that access and refresh token could be used for next requests. Except manual authorization for the first time - works fine

Gmail API: How to simply authenticate a User and get a list of their messages?

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()

Retrieve ClassWork from GoogleClassroomApi [403] Python

I am trying to retreive the classwork of each course from Google Classroom API.I have succeeded in getting all the courses, but I am stuck on the course work: <HttpError 403 when requesting https://classroom.googleapis.com/v1/courses/167997334462/courseWork?alt=json returned "Request had insufficient authentication scopes.">.
This is the code I am using:
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/classroom.coursework.students.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.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(
r"\test\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('classroom', 'v1', credentials=creds)
# Call the Classroom API
course_work_results = service.courses().courseWork().list(courseId="167997334462").execute()
[...]
if __name__ == '__main__':
main()
I have generated the credidentials using admin account; I've also tried several different Scopes, but same error.
Could you guys please help me here?
I am using Python 3.9.
Thanks,
Alexandru
Since you are using the scope
https://www.googleapis.com/auth/classroom.coursework.students.readonly,
I assume you are a student.
Students are only allowed to access course work of the courses where they are accepted course participants.
Trying to retrieve the course work of another course will result in an 403 error.
If you are not a student, but an Admin of your Google Workspace domain, you should use a wider scope, e.g.
https://www.googleapis.com/auth/classroom.coursework.me.readonly.
Please mind that after changing the scopes in your source code you need to delete your token file to trigger new authentication flow.

Categories