Google Cloud Endpoints: Authentication issues (error 403) - python

I'm trying to connect to my Google Cloud Endpoints API that is running as an Appengine app:
#endpoints.api(name='helloworldendpoints', allowed_client_ids=["1234", "12345"], version='v1', auth_level=endpoints.AUTH_LEVEL.REQUIRED)
class HelloWorldApi(remote.Service):
...
The API request is as follows:
scopes = ["https://www.googleapis.com/auth/userinfo.email"]
credentials = ServiceAccountCredentials.from_json_keyfile_name("CloudEndpointsClient.json", scopes)
from httplib2 import Http
http_auth = credentials.authorize(Http())
from apiclient.discovery import build
api_root = 'https://myapp.appspot.com/_ah/api'
api = 'helloworldendpoints'
version = 'v1'
discovery_url = '%s/discovery/v1/apis/%s/%s/rest' % (api_root, api, version)
service = build(api, version, discoveryServiceUrl=discovery_url)
response = service.myFunction(myparameter = "123456").execute(http=http_auth)#
print response
The requests work well if I remove authentication requirements.
I know that authentication works since the error changes if after authenticating.
The error message I'm getting is:
googleapiclient.errors.HttpError: https://my-app.appspot.com/_ah/api/helloworldendpoints/v1/obtainScoreFromEmail?myparameter=1234&alt=json returned "Access Not Configured. has not been used in project 123456789 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/helloworldendpoints/overview?project=123456789 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.">
I cannot enable the API in my Google Cloud Project, since the API does not exist.

What I found to work is a hack around. I used a user authentication (instead of server) on the same project for the same API which worked (https://cloud.google.com/endpoints/docs/frameworks/python/access_from_python).
After I switched back to my initial server auth. method it started working.

Related

What permissions are required for validating Google Store In-App Purchases?

I am trying to validate user purchase with the token received from the client (internal release).
For that I am using Python script with Google Python API Client (https://github.com/googleapis/google-api-python-client).
import httplib2
from oauth2client.service_account import ServiceAccountCredentials
token = "token received from the client"
http = httplib2.Http(timeout=self.http_timeout)
credentials = ServiceAccountCredentials.from_json_keyfile_name(
"./service_account.json", "https://www.googleapis.com/auth/androidpublisher"
)
http = credentials.authorize(http)
result = build("androidpublisher", "v3", http=http)\
.purchases()\
.products()\
.get(packageName="<package name>", productId="<subscription id>", token=token)\
.execute(http=http)
The response I am getting from this call is:
HttpError 401 when requesting https://www.googleapis.com/androidpublisher/v3/applications/<package name>/purchases/products/<subscription id>/tokens/<token>?alt=json returned "The current user has insufficient permissions to perform the requested operation."
The service user being used is give admin permissions to the account (for the sake of the test) in Google Play Console, and set to be "Project Owner" in "Google Cloud Console" console (for the sake of the test again).
What seems to be wrong here?
The 'Owner' permissions are sufficient to receipt validation [Source].
The error you're getting is most likely a propagation issue where it can actually take ~24hrs for the service credentials to go into effect throughout the system.

Google OAuth client is using the wrong project_id from the json file- Python

My Python (3.6.7) code uses oauth2client to access Google Photos APIs. It successfully authenticates, but when it tries to access the Google Photos albums, it seems to be using the username as the project_id.
from __future__ import print_function
from apiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
# Setup the Photo v1 API
SCOPES = 'https://www.googleapis.com/auth/photoslibrary.readonly'
store = file.Storage('credentials.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('scripts/client_id.json', SCOPES)
creds = tools.run_flow(flow, store)
service = build('photoslibrary', 'v1', http=creds.authorize(Http()))
# Call the Photo v1 API
results = service.albums().list(
pageSize=10, fields="nextPageToken,albums(id,title)").execute()
items = results.get('albums', [])
if not items:
print('No albums found.')
else:
print('Albums:')
for item in items:
print('{0} ({1})'.format(item['title'].encode('utf8'), item['id']))
When executing the above code, it prompts me the auth page. When I successfully authenticate, it shows me the following error:
HttpError 403 when requesting {URL} returned "Photos Library API has not been used in project 123456 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/photoslibrary.googleapis.com/overview?project=123456 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.">
Interestingly, the number in bold 123456 (obviously changed) is actually the first part of the client_id found in the client_id.json
But the project_id looks something like this: test1-235515
So what I got from this error is that the oauth2client client is passing the client_id instead of the project_id. So even though I have enabled the Photos API, it will never access it correctly.
Please help with this error. How can I manually change the project_id?
The project ID is different from the project number. You will be able to see both in your Google Cloud Console configuration. See this documentation for more on how to identify your projects [1].
A single Google Cloud project can have many different OAuth client IDs configured. See this documentation for information about creating OAuth client credentials [2]. You should be only have to make sure that the client you created belongs to the project for which you have enabled APIs. Going to the URL provided in the error message should take you to the right configuration page.
[1] https://cloud.google.com/resource-manager/docs/creating-managing-projects#identifying_projects
[2] https://support.google.com/cloud/answer/6158849?hl=en

Receiving 403 error when accessing G Suite Admin SDK using google-api-python-client

i'm trying to write a simple script that will get the users list from my Google G Suite domain from Directory API of Admin SDK using google-api-python-client. I've read tons of documentation, tried hundreds of various requests, but always receive: googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/admin/directory/v1/users?domain=example.com&alt=json returned "Not Authorized to access this resource/api"> error.
This is what i did:
In the Google Developer console https://console.developers.google.com:
created a new project
enabled 'Admin SDK' API.
created a Service account Key
saved the generated key into a 'service-key.json' file
In the G Suite Admin console:
API access is enabled
Admin SDK is enabled
'Client ID' of the service key ^^ is authorized to 'View users on your domain', scope: https://www.googleapis.com/auth/admin.directory.user.readonly in the API client access console section.
Created a simple test script:
#!/usr/bin/env python3
import json
from httplib2 import Http
from oauth2client.service_account import ServiceAccountCredentials
from apiclient.discovery import build
scopes = ['https://www.googleapis.com/auth/admin.directory.user.readonly']
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'service-key.json', scopes)
account = credentials.authorize(Http())
service = build('admin', 'directory_v1', http=account)
response = service.users().list(domain='example.com').execute()
print(response)
Other:
tried also 'Enable G Suite Domain-wide Delegation' (used create_delegated() method on a ServiceAccountCredentials object)
i see in the Google Developer Console - Dashboard, that the script is issuing the proper requests - can see the 'directory.users.list' API methods are being issued, but fails with 403 error
Thanks in advance for any help!
#Mr.Rebot's suggestion worked for me. The basic service account wouldn't work but impersonating the admin (which you have enabled it to do), allows the API call to pass.

Google cloud speech api throwing 403 when trying to use it

I'm using python with google cloud speech api I did all the steps in "How to use google speech recognition api in python?" on ubuntu and on windows as well and when I trying to run the simple script from here - "https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/speech/api/speech_rest.py"
I get the next error:
<HttpError 403 when requesting https://speech.googleapis.com/$discovery/rest?version=v1beta1 returned "Google Cloud Speech API has not been used in project google.com:cloudsdktool before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/speech.googleapis.com/overview?project=google.com:cloudsdktool then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.">
what is weird is that I don't have project by the name "cloudsdktool"
I run "gcloud init", and linked the json file that I got when I created service account key with "gcloud auth activate-service-account --key-file=jsonfile" command,
I tried in linux to create google credentials environment variable and still I get the same massage
So I found two ways to fix that problem:
1 - if using google cloud sdk and the cloud speech is in beta version you need to run 'gcloud beta init' instead of 'gcloud init' and then provide the json file
2 - if you don't want to use the cloud sdk from google you can pass the json file straight in python app
here are the methods for this:
from oauth2client.client import GoogleCredentials
GoogleCredentials.from_stream('path/to/your/json')
then you just create scope on the creds and authorizing or if using grpc(streaming) you pass it to the header just like in the example.
here are the changed script for the grpc:
def make_channel(host, port):
"""Creates an SSL channel with auth credentials from the environment."""
# In order to make an https call, use an ssl channel with defaults
ssl_channel = implementations.ssl_channel_credentials(None, None, None)
# Grab application default credentials from the environment
creds = GoogleCredentials.from_stream('path/to/your/json').create_scoped([SPEECH_SCOPE])
# Add a plugin to inject the creds into the header
auth_header = (
'Authorization',
'Bearer ' + creds.get_access_token().access_token)
auth_plugin = implementations.metadata_call_credentials(
lambda _, cb: cb([auth_header], None),
name='google_creds')
# compose the two together for both ssl and google auth
composite_channel = implementations.composite_channel_credentials(
ssl_channel, auth_plugin)
return implementations.secure_channel(host, port, composite_channel)

Can't authorize with google plus API

I am trying to authorize my app using google plus. However, everything I've tried always gives me a 404 when I use the people service and attempt to get 'me', except when I log in with the user who created the Google+ API app. It doesn't make any sense to my why that would be the case.
from httplib2 import Http
from apiclient.discovery import build
credential = gp_client.step2_exchange(request.REQUEST)
http = Http()
http = credential.authorize(http)
service = build("plus", "v1", http=http)
o = service.people().get(userId='me').execute()
The same is also true when I use the Google+ explorer:
http://code.google.com/apis/explorer/#_s=plus&_v=v1&_m=people.get&fields=emails
If I switch to private with the user who created the API, then I can fetch 'me', but if I authorize another user, then I can't fetch 'me'.
Any ideas what is happening?
Finally figured out what this was. Google lets you authorize any google account for an app. However, if the authorizing user hasn't upgraded to Google+, when the app makes its first Google+ API request, the request will 404. This is mind boggling, because when I setup the OAuth2WebServerFlow I specified "plus.me" as the scope... IMHO Google should tell the user to upgrade to Google+ when they try to authorize this OAuth request.
gp_client = OAuth2WebServerFlow(
settings.GOOGLE_PLUS_CONSUMER_ID,
settings.GOOGLE_PLUS_CONSUMER_SECRET,
scope='https://www.googleapis.com/auth/plus.me',
)

Categories