Insufficient permission Site verification Google - python

I want to use python and the verification site api (v1) to verify website in my webmaster tools. In this example I want to get all verified sites using the verification api, because that function doesn't have parameters. (I know that it's possible via the webmaster tools, as well)
#!/usr/bin/python
import httplib2
from apiclient import errors
from apiclient.discovery import build
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.file import Storage
http = httplib2.Http()
storage = Storage('credentials')
storage_verify = Storage('credentials_verify')
credentials = storage.get()
credentials_verify = storage_verify.get()
http_wm = credentials.authorize(http)
http_sv = credentials_verify.authorize(http)
webmasters_service = build('webmasters', 'v3', http=http_wm)
verification_service = build('siteVerification', 'v1', http=http_sv)
site_list = webmasters_service.sites().list().execute()
print(site_list)
# this line generates the error
verified_site_list = verification_service.webResource().list().execute()
print(verified_site_list)
There is an insufficient permission error:
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/siteVerification/v1/webResource?alt=json returned "Insufficient Permission">
I have read and write access for the siteVerification api (I've checked my token here: https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=TOKEN )
Any ideas what I'm doing wrong or how I can debug the code?

Make sure you read and understand https://developers.google.com/site-verification/v1/invoking in its entirety. Especially you need to appreciate:
Verify a new site
To verify a site,
- First request a verification token by calling getToken.
- Place the token on your site using whatever method you choose.
- Ask Google to verify that the site is yours, using the insert operation.
All you need to do is properly construct two requests, getToken and insert. What "properly" means, is discussed in all detail in the docs I linked above.
If you really need help with code, you need to show a minimal working example so that we can reproduce the error you retrieve.

I found my problem...
These two lines:
http_wm = credentials.authorize(http)
http_sv = credentials_verify.authorize(http)
uses the same http object which isn't allowed.
I use this code now:
http_wm = httplib2.Http()
http_sv = httplib2.Http()
http_wm = credentials.authorize(http_wm)
http_sv = credentials_verify.authorize(http_sv)

Related

msal access token not compatible with sharepoint online rest apis

I am migrating my code from ADAL to msal library. I have done all the necessary changes .
Trying to get access token by using the following code:
app = msal.ConfidentialClientApplication(
config["client_id"], authority=config["authority"],
client_credential=config["secret"] )
result = None
result = app.acquire_token_silent(config["scope"], account=None)
if not result:
result = app.acquire_token_for_client(scopes=config["scope"])
#With this code i am getting the (access token) but when using
headers = self.get_headers()
request = requests.get(url=folder_path, headers=headers, data={})
getting request response [401enter code here].
I cannot access any resource in the _api/web/lists/... api. SharePoint is a bit odd having multiple APIs to get data (Graph endpoint and _api endpoint), but before I dive into an MSAL conversion I wanted to know whether it actually supports access tokens to this SharePoint _api. I have tried without success. I cannot find anything in the Microsoft documentation about the supported APIs so I was hoping for some guidance. Note our application is currently working with ADAL. Thanks!

Authentification issue to BigQuery API REST using Python

I would like to make a HTTP call to this resource :
https://bigquery.googleapis.com/bigquery/v2/projects/{projectId}/jobs
As I read to the documentation I use an API key generated from my GCP project to be authenticated. So with requests I make a simple call like this:
import requests
params = {'key': 'MY_API_KEY'}
base_url = 'https://bigquery.googleapis.com'
project_id = 'MY_PROJECT_ID'
r = requests.get(f'{base_url}/bigquery/v2/projects/{project_id}/jobs', params=params)
Unfortunately it returns a response 401 and I can't figure out why.
Thanks a lot and have a nice day !
Update code after guillaume blaquiere reply :
from google.auth.transport.requests import AuthorizedSession
from google.oauth2 import service_account
base_url = 'https://bigquery.googleapis.com'
project_id = 'project_id'
credentials = service_account.Credentials.from_service_account_file(
'service_account.json',
scopes=['https://www.googleapis.com/auth/bigquery',
'https://www.googleapis.com/auth/cloud-platform'],
)
authed_session = AuthorizedSession(credentials)
response = authed_session.request('GET', f'{base_url}/bigquery/v2/projects/{project_id}/jobs')
print(response.json())
# this returns : {'etag': 'tAZvk1k2f2GY8yHaQF7how==', 'kind': 'bigquery#jobList'}
The API Key no longer works for a large number of Google API. Only some legacy continue to accept an API key.
Now, you need an authenticated request. You can find exemple in the google-auth python library documentation. Look at Refresh and Authorized_session.
Don't hesitate to comment if you need help about the credential obtention, I can also help you on this.
EDIT
When you perform the request, it's, by default, only on the current user. In your case, it's the service account when you use the Python code, and your User account when you use the API Explorer (the swagger like in the Google Documentation).
In your case, I guess that your service account has never performed a job (query or load job) and thus, there is no entry for it.
According with the documentation, is you want to see all the user jobs, you have to add the param ?allUsers=true at the end of your URL
response = authed_session.request('GET', f'{base_url}/bigquery/v2/projects/{project_id}/jobs?allUsers=true')

People API returns no connections when authenticating via Service Account [duplicate]

I'm trying to programmatically access the list of contacts on my own personal Google Account using the Python Client Library
This is a script that will run on a server without user input, so I have it set up to use credentials from a Service Account I set up. My Google API console setup looks like this.
I'm using the following basic script, pulled from the examples provided in the API docs -
import json
from httplib2 import Http
from oauth2client.service_account import ServiceAccountCredentials
from apiclient.discovery import build
# Only need read-only access
scopes = ['https://www.googleapis.com/auth/contacts.readonly']
# JSON file downloaded from Google API Console when creating the service account
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'keep-in-touch-5d3ebc885d4c.json', scopes)
# Build the API Service
service = build('people', 'v1', credentials=credentials)
# Query for the results
results = service.people().connections().list(resourceName='people/me').execute()
# The result set is a dictionary and should contain the key 'connections'
connections = results.get('connections', [])
print connections #=> [] - empty!
When I hit the API it returns a result set without any 'connections' key. Specifically it returns -
>>> results
{u'nextSyncToken': u'CNP66PXjKhIBMRj-EioECAAQAQ'}
Is there something pertaining to my setup or code that's incorrect? Is there a way to see the response HTTP status code or get any further detail about what it's trying to do?
Thanks!
Side note: When I try it using the "Try it!" feature in the API docs, it correctly returns my contacts. Although I doubt that uses the client library and instead relies on user authorization via OAuth
The personFields mask is required. Specify one or more valid paths. Valid paths are documented at https://developers.google.com/people/api/rest/v1/people.connections/list/.
Additionally, use fields mask to specify which fields are included in a partial response.
Instead of:
results = service.people().connections().list(resourceName='people/me').execute()
... try:
results = service.people().connections().list(resourceName='people/me',personFields='names,emailAddresses',fields='connections,totalItems,nextSyncToken').execute()
Here is a working demo. I just tested it right now. Python 3.5.2
google-api-python-client==1.6.4
httplib2==0.10.3
oauth2client==4.1.2
You can save it to demo.py and then just run it. I left the create_contact function in case you might want to use it and have one more example on the API usage.
CLIENT_ID and CLIENT_SECRET are environment variables so I don't accidentally share that in code.
"""Google API stuff."""
import httplib2
import json
import os
from apiclient.discovery import build
from oauth2client.file import Storage
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run_flow
CLIENT_ID = os.environ['CLIENT_ID']
CLIENT_SECRET = os.environ['CLIENT_SECRET']
SCOPE = 'https://www.googleapis.com/auth/contacts'
USER_AGENT = 'JugDemoStackOverflow/v0.1'
def make_flow():
"""Make flow."""
flow = OAuth2WebServerFlow(
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
scope=SCOPE,
user_agent=USER_AGENT,
)
return flow
def get_people():
"""Return a people_service."""
flow = make_flow()
storage = Storage('info.dat')
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = run_flow(flow, storage)
http = httplib2.Http()
http = credentials.authorize(http)
people_service = build(serviceName='people', version='v1', http=http)
return people_service
def create_contact(people, user):
"""Create a Google Contact."""
request = people.createContact(
body={
'names': [{'givenName': user.name}],
'phoneNumbers': [
{'canonicalForm': user.phone, 'value': user.phone}],
}
)
return request.execute()
def demo():
"""Demonstrate getting contacts from Google People."""
people_service = get_people()
people = people_service.people()
connections = people.connections().list(
resourceName='people/me',
personFields='names,emailAddresses,phoneNumbers',
pageSize=2000,
)
result = connections.execute()
s = json.dumps(result)
# with open('contacts.json', 'w') as f:
# f.write(s)
return s
if __name__ == '__main__':
print(demo())
With service account, in DwD - G Suite Domain-wide Delegation, is necessary impersonate or delegate user in this way
delegate = credentials.create_delegated('user#xxxx.xxx')
For fellow googlers: I have the same problem using the JS API.
I succeded on my personal gmail address, but not on my work one (g-suite) neither on my secondary gmail address.
Can't see the pattern. It's possible that the work one has contact listing deactivated.

Using Google+ API causes HttpAccessTokenRefreshError

I want to use server-side communication with the Google+ API to retrieve the current user's profile information. I log in the user according to the Google example for python:
credentials = client.credentials_from_clientsecrets_and_code(
CLIENT_SECRET_FILE,
['https://www.googleapis.com/auth/drive.appdata', 'profile', 'email'],
code)
Then I call the Google+ API:
http_auth = credentials.authorize(httplib2.Http())
service = build('plus', 'v1', http = http_auth)
google_request = service.people().list(userId = 'me', collection = 'visible')
result = google_request.execute()
This thows the following error:
HttpAccessTokenRefreshError: invalid_grant
Does anyone have an idea what I can do about this?
I solved the problem by using the correct method people().get() instead of people().list()
At first I wanted to delete the question because the topic seems silly but I copy-pasted the wrong API call from a code sample on Github and therefore I can imagine that others run into this issue as well.

How would one convert/wrap a HTTPLib2 instance as a Session?

I know the title is a big wonky and I apologize for that. The dilemma I have is that gspread uses Session and the Google APIs client library for Python uses HTTPLib2. I have a service account that I have working with the Google API client and want to take the authenticated httplib2.Http() instance and wrap it so that gspread can use it like a Session object.
UPDATE: Fixed with update 103 to gspread. Based on Jay Lee's awesome answer below, here's how to initialize the gspread Client with a service account in Python 2.7 (you will need to replace /path/to/service-account.p12 and set sa_id):
import gspread
from oauth2client.client import SignedJwtAssertionCredentials
from apiclient.discovery import build
# ...
with open('/path/to/service-account.p12') as f: sa_key = f.read()
credentials = SignedJwtAssertionCredentials(
sa_id, sa_key, 'https://spreadsheets.google.com/feeds')
http = httplib2.Http()
http = credentials.authorize(http)
build('drive', 'v2', http = http)
access_token = http.request.credentials.access_token
gspread_auth_headers = {'Authorization' : 'Bearer %s' % access_token}
gspread_session = gspread.httpsession.HTTPSession(headers=gspread_auth_headers)
fakeauth = ('notmyusername#gmail.com', 'notmypassword')
client = gspread.Client(fakeauth, http_session=gspread_session)
# https://github.com/burnash/gspread/issues/103
if False == hasattr(client, "session"):
client = gspread.Client(fakeauth)
client.session = gspread_session
Now you can use client as you normally would. Whew!
A quick look at gspread indicates it's using the old ClientLogin authentication protocol which is deprecated. But you should be able to grab the access token from the httplib2.Http() instance and apply the same header to the gspread session (effectively getting gspread to use OAuth 2.0 also):
http = <<<Your existing, authenticated httplib2.Http() object)>>>
access_token = http.request.credentials.access_token
gspread_auth_headers = {'Authorization': 'Bearer %s' % access_token}
gspread_session = gspread.httpsession.HTTPSession(headers=gspread_auth_headers)
my_gspread = gspread.Client(auth=('notmyusername#gmail.com', 'notmypassword'), http_session=gspread_session)
notmyusername#gmail.com and notmypassword are random strings here, they're only needed because gspread.Client expects auth to be a tuple passed to it and they won't be passed to Google unless you call my_gspread.login() (which you won't).
You will need to watch out for and catch expired access_tokens. If gspread throws an error about invalid tokens, you should catch it, call http.request.credentials.refresh() to get a new access token and then recreate the gspread session with the fresh token.

Categories