I've been trying to get this to work for awhile and I can't get passed this error code I'm getting.
My goal with this code is to set a forwarding email address in gmail. Here is the Google documentation: https://developers.google.com/gmail/api/guides/forwarding_settings
I've copied and pasted the code and I get the same error message:
googleapiclient.errors.HttpError: <HttpError 400 when requesting https://www.googleapis.com/gmail/v1/users/me/settings/forwardingAddresses?alt=json returned "Bad Request">
Bad request is by far the most frustrating error code to get in return. I'm using a service account with domain-wide delegation so I don't think it's a permissions issue. I've copied the code so it's hard to believe the json package is incorrect. I've looked all over the internet and cannot find example code of anyone actually using this feature. I'm afraid GAM will be my only option.
def test():
key_path = 'tokens/admin_client.json'
API_scopes =['https://www.googleapis.com/auth/gmail.settings.sharing','https://www.googleapis.com/auth/gmail.settings.basic']
credentials = service_account.Credentials.from_service_account_file(key_path,scopes=API_scopes)
gmail_service = build('gmail', 'v1', credentials=credentials)
address = { 'forwardingEmail': 'user2#example.com' }
gmail_service.users().settings().forwardingAddresses().create(userId='me', body=address).execute()
Please try this code I made. It is working for me:
from googleapiclient import discovery, errors
from oauth2client import file, client, tools
from google.oauth2 import service_account
SERVICE_ACCOUNT_FILE = 'service_account.json'
SCOPES = ['https://www.googleapis.com/auth/gmail.settings.sharing']
# The user we want to "impersonate"
USER_EMAIL = "user#domain"
ADDRESS = { 'forwardingEmail': 'user2#domain' }
# Set the crendentials
credentials = service_account.Credentials.\
from_service_account_file(SERVICE_ACCOUNT_FILE, scopes= SCOPES)
# Delegate the credentials to the user you want to impersonate
delegated_credentials = credentials.with_subject(USER_EMAIL)
try:
# Build the Gmail Service
service = discovery.build('gmail', 'v1', credentials=delegated_credentials)
# Create the forwardingAddresses:Create endpoint
result = service.users().settings().forwardingAddresses().\
create(userId='me', body=ADDRESS).execute()
if result.get('verificationStatus') == 'accepted':
body = {
'emailAddress': result.get('forwardingEmail'),
'enabled': True,
'disposition': 'trash'
}
# If accepted, update the auto forwarding
result_update = service.users().settings().\
updateAutoForwarding(userId='me', body=body).execute()
print(result_update)
# Handle errors if there are
except errors.HttpError as err:
print('\n---------------You have the following error-------------')
print(err)
print('---------------You have the following error-------------\n')
I based the code I'm providing you from Managing Forwarding (the same link you shared), you can also check the Users.settings.forwardingAddresses and the Python API library
for more information about the Gmail API library and the endpoints contained there.
Notice
You mentioned in one of your comments from another answer that when using .with_subject(arg) you're getting the error "the user did not have permission". Check OAuth: Managing API client access, it will provide you with some steps to enable the authorizations needed for the occasions when you are using a service account and G Suite.
You are using a service account, which does not have access to Gmail.
You can either use the service account to impersonate GSuite users or use OAuth to login as a user directly.
Related
I have started to develop some apis to create users in my G suite directory.
I followed the service account tutorials along with the Directory tutorials for python. The code I have is very simple just to test out how it will work.
from google.oauth2 import service_account
from googleapiclient.discovery import build
SCOPES = ['https://www.googleapis.com/auth/admin.directory.user']
SERVICE_ACCOUNT_FILE = 'file'
creds = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = build('admin', 'directory_v1', credentials=creds)
results = service.users().list(customer='i am not sure what customer is', maxResults=10, orderBy='email').execute()
#this line produces the error.
#Vscode also states the service has no member users. But I did install all #the libraries
users = results.get('users', [])
print(users)
The documentation to me is unclear about most things. When I run this I get
googleapiclient.errors.HttpError: <HttpError 400 when requesting https://www.googleapis.com/admin/directory/v1/users?customer=students&maxResults=10&orderBy=email&alt=json returned "Bad Request">
When I change customer from my_customer to something else I get Invalid Input.
Any suggestions to what may cause this error and preferably how to work with this api via a service account?
Now I did enable the directory api and create the service account and downloaded the service account file as well. Am I missing a step?
I would also prefer if someone has a better documentation that I was unable to find.
Finally I resolved this issue by setting another parameter "subject" when calling "service_account.Credentials.from_service_account_file".
Ensure that the service account has domain-wide-delegation enabled and has the proper scopes.
I am try to access dbm api , I am authenticating the url using service account please find the sample code below
from oauth2client.service_account import ServiceAccountCredentials
from apiclient.discovery import build
from httplib2 import Http
scopes =['https://www.googleapis.com/auth/doubleclickbidmanager']
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'path/to/key/.jsonfile', scopes=scopes)
http_auth = credentials.authorize(Http())
body={}
dbm = build('doubleclickbidmanager', 'v1', http=http_auth)
print dbm
request = dbm.lineitems().downloadlineitems(body=body).execute()
print request
If I use oauth mechanism to authenticate the url the code is running properly, since I don't want user interaction, I need server to server mechanism so I used service account
Steps which I tried:
I have created the service account and downloaded the json key file and used in the code but when I try to run my code it throws the following error:
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/doubleclickbidmanager/v1/lineitems/downloadlineitems?alt=json returned "You are not authorized to use DoubleClick Bid Manager API. Please contact dbm-support#google.com.">
Please help , thanks in advance.
As others have said here, you want to log in to the DBM site and add your service account as a user:
Then, per this documentation, you can set up service account credentials using your client secrets json file. If you want that service account to be able to access reports you've created in DBM under your user account (what you log in with) you need to delegate domain-wide authority:
delegated_credentials = credentials.create_delegated('user#example.org')
http_auth = delegated_credentials.authorize(Http())
dbm = build('doubleclickbidmanager', 'v1', http=http_auth)
queries = dbm.queries().listqueries().execute()['queries']
A service account isn't you its a dummy user it has its on Google drive account for example, and by default it doesn't have access to any DoubleClick Bid Manager APIs. Service accounts need to be pre authorized to be able to access private data. So for it to be able to access your double click data you are going to have to grant it access.
Normally with any other API I would say you take the service account email address and add it as a user. I don't have access to double click so I am not even sure if you can add other users manually. They don't have anything in the documentation about service accounts kind of makes me think its not supported. Let us know if you manage to get it to work.
I've been having trouble over the past few days using the Google Directory API in the Admin SDK for Google Apps. The documentation leaves a lot to be desired and when I contacted Google Apps Enterprise support they indicated they do not support the API. I am using the most recent Python API client library provided by Google as they suggest this is the best way to go. I've logged in to the Google API Console and created a Service Account and downloaded the OAuth2 key. I've also turned on the Admin SDK in the console. Here is my code:
f = file("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-privatekey.p12", "rb")
key = f.read()
f.close()
credentials = SignedJwtAssertionCredentials(
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx#developer.gserviceaccount.com",
key,
scope = "https://www.googleapis.com/auth/admin.directory.orgunit"
)
http = httplib2.Http()
http = credentials.authorize(http)
directoryservice = build("admin", "directory_v1", http=http)
orgunits = directoryservice.orgunits().list(customerId='XXXXXXX').execute(http=http)
pprint.pprint(orgunits)
Note that customerId is our Google Apps customer ID. I tried it with "my_customer" as Google seems to indicate should work when using an account that is super admin, but I receive the return "invalid customerId" when I try it that way. So I hardcoded our actual customerId.
When harcoded always receive the return "Login Required" but it seems as if the authentication process is working as the directory object gets created via the build command. Am I doing something wrong?
Note, I also read somewhere that sometimes the request needs to come from a domain account rather than the Service Account and to do this you need to add:
sub = "domain_account_superadmin#example.com"
In the SignedJwtAssertionCredentials call... which I tried, but then receive the message "access_denied"
Thanks in advance for suggestions.
See the google drive example here: https://developers.google.com/drive/delegation
Don't forget to delegate domain wide authority for the service account and scopes.
Here is an example for listing organization units via service account:
import sys
import apiclient.discovery
import oauth2client.client
import httplib2
import pprint
# see example for using service account here:
# https://developers.google.com/drive/delegation
def main (argv):
scopes = ('https://www.googleapis.com/auth/admin.directory.orgunit')
service_account_email = 'xxx#developer.gserviceaccount.com'
acting_as_user = 'yyy#zzz' # must have the privileges to view the org units
f = file('key.p12', 'rb')
key = f.read()
f.close()
credentials = oauth2client.client.SignedJwtAssertionCredentials(
service_account_email,
key,
scope=scopes,
sub=acting_as_user
)
http = httplib2.Http()
http = credentials.authorize(http)
directoryservice = apiclient.discovery.build('admin', 'directory_v1', http=http)
response = directoryservice.orgunits().list(customerId='my_customer').execute(http=http)
pprint.pprint(response)
if __name__ == '__main__':
main(sys.argv)
I'm getting an error while calling the Reports API:
<HttpError 403 when requesting https://www.googleapis.com/admin/reports/v1/usage/users/all/dates/2013-08-01?alt=json&maxResults=1 returned "Caller does not have access to the customers reporting data.">
Have anyone seen this error before? What am I missing?
I just can't see why this is showing or what I should be checking.
Regards.
EDIT:
Auth:
credentials = SignedJwtAssertionCredentials(
service_account_name='5163XXXXX#developer.gserviceaccount.com',
private_key=oauth2_private_key,
scope='https://www.googleapis.com/auth/admin.reports.usage.readonly')
# https://developers.google.com/api-client-library/python/guide/thread_safety
http = credentials.authorize(httplib2.Http())
service = apiclient.discovery.build('admin', 'reports_v1', http=http)
The actual call:
result = service.userUsageReport().get(
userKey='all',
date='2013-08-01',
maxResults=1).execute()
Other APIs just work fine with that service account.
'https://www.googleapis.com/auth/admin.reports.usage.readonly' has been properly added to OAuth2 domain config page.
Try:
credentials = SignedJwtAssertionCredentials(
service_account_name='5163XXXXX#developer.gserviceaccount.com',
private_key=oauth2_private_key,
scope='https://www.googleapis.com/auth/admin.reports.usage.readonly',
sub='super-admin#yourdomain.com')
when using Service Accounts with Admin SDK, you still need to act on behalf of an admin within the Google Apps instance.
Also, make sure that the Service Account Client ID has been granted rights to use the Reports API scopes in the Google Apps Control Panel. The Google Drive docs describe this process well, just sub in the Reports scopes instead.
I'm trying to connect to the google doubeclick api through a service account (client email and p12 certificate), using the python client library as in the following example:
http://code.google.com/p/google-api-python-client/source/browse/samples/service_account/tasks.py
It's returning me an empty access_token:
In [9]: type(credentials.access_token)
Out[9]: <type 'NoneType'>
What is the significance of this? Is there something I am likely doing wrong? I have also tried accessing the tasks api as in the example (thinking that possibly the doubleclick api is not a supported scope) but same result.
UPDATE (example code):
from oauth2client.client import SignedJwtAssertionCredentials
import httplib2
from adspygoogle.dfp import DfpClient
f = file('/path/to/.ssh/google-api.p12', 'rb')
key = f.read()
f.close()
credentials = SignedJwtAssertionCredentials('<email>', key, scope='https://www.google.com/apis/ads/publisher')
credentials.refresh(http)
http = httplib2.Http()
http = credentials.authorize(http)
client = DfpClient.DfpClient(headers={'networkCode': '<code>', 'applicationName': 'test', 'userAgent': 'test', 'oauth2credentials': credentials})
inventory_service = client.GetInventoryService()
inventory_service.getAdUnitsByStatement({'query':''})
ERROR:
DfpAuthenticationError: [AuthenticationError.NO_NETWORKS_TO_ACCESS # ]
The NO_NETWORKS_TO_ACCESS error specifically means that you did authenticate to the API endpoint but that your account isn't associated with a network. Search for that error on this page https://developers.google.com/doubleclick-publishers/docs/reference/v201203/InventoryService?hl=en.
You either need to have the Google account you are authenticating as invited to the network via the DoubleClick User Interface or you need to use impersonation.
A more specific writeup on DFP API and service accounts was recently posted https://developers.google.com/doubleclick-publishers/docs/service_accounts to the documentation. I suggest you look at the alternative section of that documentation to determine if you might prefer an OAuth 2.0 installed flow.